GLboolean select_segment_in_viewscreen(const GLfloat *a, const GLfloat *b) { /* Return True is the segment is fully inside viewscreen or cross the viewscreen Viewscreen is (-1,-1)(+1,+1) False if completly outside */ // Fast either point inside viewport if (select_point_in_viewscreen(a)) return true; if (select_point_in_viewscreen(b)) return true; // Using Liang-Barsky algorithm GLfloat vx, vy; vx=b[0]-a[0]; vy=b[1]-a[1]; GLfloat p[4] = {-vx, vx, -vy, vy}; GLfloat q[4] = {a[0] + 1.0f, +1.0f - a[0], a[1] + 1.0f, +1.0f - a[1]}; GLfloat u1 = 0.0f; GLfloat u2 = 1.0f; for (int i=0; i<4; i++) { if (p[i] == 0.0f) { if (q[i]<0.0f) return false; } else { GLfloat t =q[i] / p[i]; if (p[i]<0.0) { if(t>u2) return false; else if(u1<t) u1 = t; } else if (p[i]>0.0) { if(t<u1) return false; else if (u2>t) u2 = t; } } } return true; }
void select_glDrawElements(const pointer_state_t* vtx, GLenum mode, GLuint count, GLenum type, GLvoid * indices) { if (count == 0) return; if (vtx->pointer == NULL) return; GLushort *sind = (GLushort*)((type==GL_UNSIGNED_SHORT)?indices:NULL); GLuint *iind = (GLuint*)((type==GL_UNSIGNED_INT)?indices:NULL); GLsizei min, max; if(sind) getminmax_indices_us(sind, &max, &min, count); else getminmax_indices_ui(iind, &max, &min, count); max++; GLfloat *vert = copy_gl_array(vtx->pointer, vtx->type, vtx->size, vtx->stride, GL_FLOAT, 4, 0, max); GLfloat zmin=1e10f, zmax=-10e6f; int found = 0; for (int i=min; i<max; i++) { select_transform(vert+i*4); ZMinMax(&glstate->selectbuf.zminoverall, &glstate->selectbuf.zmaxoverall, vert+i*4); } #define FOUND() { \ found = 1; \ glstate->selectbuf.hit = 1; \ } if(sind) { for (int i=0; i<count; i++) { switch (mode) { case GL_POINTS: if (select_point_in_viewscreen(vert+sind[i]*4)) { ZMinMax(&zmin, &zmax, vert+sind[i]*4); FOUND(); } break; case GL_LINES: if (i%2==1) { if (select_segment_in_viewscreen(vert+sind[(i-1)]*4, vert+sind[i]*4)) { ZMinMax(&zmin, &zmax, vert+sind[i-1]*4); ZMinMax(&zmin, &zmax, vert+sind[i]*4); FOUND(); } } break; case GL_LINE_STRIP: case GL_LINE_LOOP: //FIXME: the last "loop" segment is missing here if (i>0) { if (select_segment_in_viewscreen(vert+sind[(i-1)]*4, vert+sind[i]*4)) { ZMinMax(&zmin, &zmax, vert+sind[i-1]*4); ZMinMax(&zmin, &zmax, vert+sind[i]*4); FOUND(); } } break; case GL_TRIANGLES: if (i%3==2) { if (select_triangle_in_viewscreen(vert+sind[(i-2)]*4, vert+sind[(i-1)]*4, vert+sind[i]*4)) { ZMinMax(&zmin, &zmax, vert+sind[i-2]*4); ZMinMax(&zmin, &zmax, vert+sind[i-1]*4); ZMinMax(&zmin, &zmax, vert+sind[i]*4); FOUND(); } } break; case GL_TRIANGLE_STRIP: if (i>1) { if (select_triangle_in_viewscreen(vert+sind[(i-2)]*4, vert+sind[(i-1)]*4, vert+sind[i]*4)) { ZMinMax(&zmin, &zmax, vert+sind[i-2]*4); ZMinMax(&zmin, &zmax, vert+sind[i-1]*4); ZMinMax(&zmin, &zmax, vert+sind[i]*4); FOUND(); } } break; case GL_TRIANGLE_FAN: if (i>1) { if (select_triangle_in_viewscreen(vert+sind[0]*4, vert+sind[(i-1)]*4, vert+sind[i]*4)) ZMinMax(&zmin, &zmax, vert+sind[0]*4); ZMinMax(&zmin, &zmax, vert+sind[i-1]*4); ZMinMax(&zmin, &zmax, vert+sind[i]*4); FOUND(); } break; default: return; // Should never go there! } } } else { for (int i=0; i<count; i++) { switch (mode) { case GL_POINTS: if (select_point_in_viewscreen(vert+iind[i]*4)) { ZMinMax(&zmin, &zmax, vert+iind[i]*4); FOUND(); } break; case GL_LINES: if (i%2==1) { if (select_segment_in_viewscreen(vert+iind[(i-1)]*4, vert+iind[i]*4)) { ZMinMax(&zmin, &zmax, vert+iind[i-1]*4); ZMinMax(&zmin, &zmax, vert+iind[i]*4); FOUND(); } } break; case GL_LINE_STRIP: case GL_LINE_LOOP: //FIXME: the last "loop" segment is missing here if (i>0) { if (select_segment_in_viewscreen(vert+iind[(i-1)]*4, vert+iind[i]*4)) { ZMinMax(&zmin, &zmax, vert+iind[i-1]*4); ZMinMax(&zmin, &zmax, vert+iind[i]*4); FOUND(); } } break; case GL_TRIANGLES: if (i%3==2) { if (select_triangle_in_viewscreen(vert+iind[(i-2)]*4, vert+iind[(i-1)]*4, vert+iind[i]*4)) { ZMinMax(&zmin, &zmax, vert+iind[i-2]*4); ZMinMax(&zmin, &zmax, vert+iind[i-1]*4); ZMinMax(&zmin, &zmax, vert+iind[i]*4); FOUND(); } } break; case GL_TRIANGLE_STRIP: if (i>1) { if (select_triangle_in_viewscreen(vert+iind[(i-2)]*4, vert+iind[(i-1)]*4, vert+iind[i]*4)) { ZMinMax(&zmin, &zmax, vert+iind[i-2]*4); ZMinMax(&zmin, &zmax, vert+iind[i-1]*4); ZMinMax(&zmin, &zmax, vert+iind[i]*4); FOUND(); } } break; case GL_TRIANGLE_FAN: if (i>1) { if (select_triangle_in_viewscreen(vert+iind[0]*4, vert+iind[(i-1)]*4, vert+iind[i]*4)) ZMinMax(&zmin, &zmax, vert+iind[0]*4); ZMinMax(&zmin, &zmax, vert+iind[i-1]*4); ZMinMax(&zmin, &zmax, vert+iind[i]*4); FOUND(); } break; default: return; // Should never go there! } } } free(vert); if(found) { if (zmin<glstate->selectbuf.zmin) glstate->selectbuf.zmin=zmin; if (zmax>glstate->selectbuf.zmax) glstate->selectbuf.zmax=zmax; } #undef FOUND }
void select_glDrawArrays(const pointer_state_t* vtx, GLenum mode, GLuint first, GLuint count) { if (count == 0) return; if (vtx->pointer == NULL) return; if (glstate->selectbuf.buffer == NULL) return; GLfloat *vert = copy_gl_array(vtx->pointer, vtx->type, vtx->size, vtx->stride, GL_FLOAT, 4, 0, count+first); GLfloat zmin=1e10f, zmax=-1e10f; int found = 0; #define FOUND() { \ found = 1; \ glstate->selectbuf.hit = 1; \ } // transform the points for (int i=first; i<count+first; i++) { select_transform(vert+i*4); ZMinMax(&glstate->selectbuf.zminoverall, &glstate->selectbuf.zmaxoverall, vert+i*4); } // intersect with screen now GLfloat *vert2 = vert + first*4; for (int i=0; i<count; i++) { switch (mode) { case GL_POINTS: if (select_point_in_viewscreen(vert2+i*4)) { ZMinMax(&zmin, &zmax, vert+i*4); FOUND(); } break; case GL_LINES: if (i%2==1) { if (select_segment_in_viewscreen(vert2+(i-1)*4, vert2+i*4)) { ZMinMax(&zmin, &zmax, vert+(i-1)*4); ZMinMax(&zmin, &zmax, vert+i*4); FOUND(); } } break; case GL_LINE_STRIP: case GL_LINE_LOOP: //FIXME: the last "loop" segment is missing here if (i>0) { if (select_segment_in_viewscreen(vert2+(i-1)*4, vert2+i*4)) { ZMinMax(&zmin, &zmax, vert+(i-1)*4); ZMinMax(&zmin, &zmax, vert+i*4); FOUND(); } } break; case GL_TRIANGLES: if (i%3==2) { if (select_triangle_in_viewscreen(vert2+(i-2)*4, vert2+(i-1)*4, vert2+i*4)) { ZMinMax(&zmin, &zmax, vert+(i-2)*4); ZMinMax(&zmin, &zmax, vert+(i-1)*4); ZMinMax(&zmin, &zmax, vert+i*4); FOUND(); } } break; case GL_TRIANGLE_STRIP: if (i>1) { if (select_triangle_in_viewscreen(vert2+(i-2)*4, vert2+(i-1)*4, vert2+i*4)) { ZMinMax(&zmin, &zmax, vert+(i-2)*4); ZMinMax(&zmin, &zmax, vert+(i-1)*4); ZMinMax(&zmin, &zmax, vert+i*4); FOUND(); } } break; case GL_TRIANGLE_FAN: if (i>1) { if (select_triangle_in_viewscreen(vert2, vert2+(i-1)*4, vert2+i*4)) { ZMinMax(&zmin, &zmax, vert); ZMinMax(&zmin, &zmax, vert+(i-1)*4); ZMinMax(&zmin, &zmax, vert+i*4); FOUND(); } } break; default: return; // Should never go there! } } free(vert); if(found) { if (zmin<glstate->selectbuf.zmin) glstate->selectbuf.zmin=zmin; if (zmax>glstate->selectbuf.zmax) glstate->selectbuf.zmax=zmax; } #undef FOUND }
void select_glDrawElements(const pointer_state_t* vtx, GLenum mode, GLuint count, GLenum type, GLvoid * indices) { if (count == 0) return; if (vtx->pointer == NULL) return; GLushort *ind = (GLushort*)indices; GLsizei min, max; getminmax_indices(indices, &max, &min, count); max++; GLfloat *vert = copy_gl_array(vtx->pointer, vtx->type, vtx->size, vtx->stride, GL_FLOAT, 3, 0, max); GLfloat tmp[3]; init_select(); GLfloat zmin=1.0f, zmax=0.0f; for (int i=min; i<max; i++) { select_transform(vert+i*3); if (vert[i*3+2]<zmin) zmin=vert[i*3+2]; if (vert[i*3+2]>zmax) zmax=vert[i*3+2]; } if (zmin<0.0f) zmin = 0.0f; if (zmax>1.0f) zmax = 1.0f; #define FOUND() { \ if (zmin<state.selectbuf.zmin) state.selectbuf.zmin=zmin; \ if (zmax>state.selectbuf.zmax) state.selectbuf.zmax=zmax; \ state.selectbuf.hit = 1; \ free(vert); \ return; \ } for (int i=0; i<count; i++) { switch (mode) { case GL_POINTS: if (select_point_in_viewscreen(vert+ind[i]*3)) FOUND(); break; case GL_LINES: if (i%2==1) { if (select_segment_in_viewscreen(vert+ind[(i-1)]*3, vert+ind[i]*3)) FOUND(); } break; case GL_LINE_STRIP: case GL_LINE_LOOP: //FIXME: the last "loop" segment is missing here if (i>0) { if (select_segment_in_viewscreen(vert+ind[(i-1)]*3, vert+ind[i]*3)) FOUND(); } break; case GL_TRIANGLES: if (i%3==2) { if (select_triangle_in_viewscreen(vert+ind[(i-2)]*3, vert+ind[(i-1)]*3, vert+ind[i]*3)) FOUND(); } break; case GL_TRIANGLE_STRIP: if (i>1) { if (select_triangle_in_viewscreen(vert+ind[(i-2)]*3, vert+ind[(i-1)]*3, vert+ind[i]*3)) FOUND(); } break; case GL_TRIANGLE_FAN: if (i>1) { if (select_triangle_in_viewscreen(vert+ind[0]*3, vert+ind[(i-1)]*3, vert+ind[i]*3)) FOUND(); } break; default: return; // Should never go there! } } free(vert); #undef FOUND }
void select_glDrawArrays(const pointer_state_t* vtx, GLenum mode, GLuint first, GLuint count) { if (count == 0) return; if (vtx->pointer == NULL) return; if (state.selectbuf.buffer == NULL) return; GLfloat *vert = copy_gl_array(vtx->pointer, vtx->type, vtx->size, vtx->stride, GL_FLOAT, 3, 0, count+first); GLfloat tmp[3]; GLfloat zmin=1.0f, zmax=0.0f; init_select(); #define FOUND() { \ if (zmin<state.selectbuf.zmin) state.selectbuf.zmin=zmin; \ if (zmax>state.selectbuf.zmax) state.selectbuf.zmax=zmax; \ state.selectbuf.hit = 1; \ free(vert); \ return; \ } // transform the points for (int i=first; i<count+first; i++) { select_transform(vert+i*3); if (vert[i*3+2]<zmin) zmin=vert[i*3+2]; if (vert[i*3+2]>zmax) zmax=vert[i*3+2]; } // intersect with screen now GLfloat *vert2 = vert + first*3; for (int i=0; i<count; i++) { switch (mode) { case GL_POINTS: if (select_point_in_viewscreen(vert2+i*3)) FOUND(); break; case GL_LINES: if (i%2==1) { if (select_segment_in_viewscreen(vert2+(i-1)*3, vert2+i*3)) FOUND(); } break; case GL_LINE_STRIP: case GL_LINE_LOOP: //FIXME: the last "loop" segment is missing here if (i>0) { if (select_segment_in_viewscreen(vert2+(i-1)*3, vert2+i*3)) FOUND(); } break; case GL_TRIANGLES: if (i%3==2) { if (select_triangle_in_viewscreen(vert2+(i-2)*3, vert2+(i-1)*3, vert2+i*3)) FOUND(); } break; case GL_TRIANGLE_STRIP: if (i>1) { if (select_triangle_in_viewscreen(vert2+(i-2)*3, vert2+(i-1)*3, vert2+i*3)) FOUND(); } break; case GL_TRIANGLE_FAN: if (i>1) { if (select_triangle_in_viewscreen(vert2, vert2+(i-1)*3, vert2+i*3)) FOUND(); } break; default: return; // Should never go there! } } free(vert); #undef FOUND }