1/************************************************************************** 2 * 3 * Copyright 2007 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28/** 29 * \brief Drawing stage for polygon culling 30 */ 31 32/* Authors: Keith Whitwell <keithw@vmware.com> 33 */ 34 35 36#include "util/u_math.h" 37#include "util/u_memory.h" 38#include "pipe/p_defines.h" 39#include "draw_pipe.h" 40 41 42struct cull_stage { 43 struct draw_stage stage; 44 unsigned cull_face; /**< which face(s) to cull (one of PIPE_FACE_x) */ 45 unsigned front_ccw; 46}; 47 48 49static inline struct cull_stage *cull_stage( struct draw_stage *stage ) 50{ 51 return (struct cull_stage *)stage; 52} 53 54/* 55 * Triangles can be culled using regular face cull. 56 */ 57static void cull_tri( struct draw_stage *stage, 58 struct prim_header *header ) 59{ 60 /* Do the regular face culling */ 61 { 62 const unsigned pos = draw_current_shader_position_output(stage->draw); 63 /* Window coords: */ 64 const float *v0 = header->v[0]->data[pos]; 65 const float *v1 = header->v[1]->data[pos]; 66 const float *v2 = header->v[2]->data[pos]; 67 68 /* edge vectors: e = v0 - v2, f = v1 - v2 */ 69 const float ex = v0[0] - v2[0]; 70 const float ey = v0[1] - v2[1]; 71 const float fx = v1[0] - v2[0]; 72 const float fy = v1[1] - v2[1]; 73 74 75 /* det = cross(e,f).z */ 76 header->det = ex * fy - ey * fx; 77 78 if (header->det != 0) { 79 /* if det < 0 then Z points toward the camera and the triangle is 80 * counter-clockwise winding. 81 */ 82 unsigned ccw = (header->det < 0); 83 unsigned face = ((ccw == cull_stage(stage)->front_ccw) ? 84 PIPE_FACE_FRONT : 85 PIPE_FACE_BACK); 86 87 if ((face & cull_stage(stage)->cull_face) == 0) { 88 /* triangle is not culled, pass to next stage */ 89 stage->next->tri( stage->next, header ); 90 } 91 } else { 92 /* 93 * With zero area, this is back facing (because the spec says 94 * it's front facing if sign is positive?). 95 * Some apis apparently do not allow us to cull zero area tris 96 * here, in case of fill mode line (which is rather lame). 97 */ 98 if ((PIPE_FACE_BACK & cull_stage(stage)->cull_face) == 0) { 99 stage->next->tri( stage->next, header ); 100 } 101 } 102 } 103} 104 105static void cull_first_tri( struct draw_stage *stage, 106 struct prim_header *header ) 107{ 108 struct cull_stage *cull = cull_stage(stage); 109 110 cull->cull_face = stage->draw->rasterizer->cull_face; 111 cull->front_ccw = stage->draw->rasterizer->front_ccw; 112 113 stage->tri = cull_tri; 114 stage->tri( stage, header ); 115} 116 117 118static void cull_flush( struct draw_stage *stage, unsigned flags ) 119{ 120 stage->tri = cull_first_tri; 121 stage->next->flush( stage->next, flags ); 122} 123 124 125static void cull_reset_stipple_counter( struct draw_stage *stage ) 126{ 127 stage->next->reset_stipple_counter( stage->next ); 128} 129 130 131static void cull_destroy( struct draw_stage *stage ) 132{ 133 draw_free_temp_verts( stage ); 134 FREE( stage ); 135} 136 137 138/** 139 * Create a new polygon culling stage. 140 */ 141struct draw_stage *draw_cull_stage( struct draw_context *draw ) 142{ 143 struct cull_stage *cull = CALLOC_STRUCT(cull_stage); 144 if (!cull) 145 goto fail; 146 147 cull->stage.draw = draw; 148 cull->stage.name = "cull"; 149 cull->stage.next = NULL; 150 cull->stage.point = draw_pipe_passthrough_point; 151 cull->stage.line = draw_pipe_passthrough_line; 152 cull->stage.tri = cull_first_tri; 153 cull->stage.flush = cull_flush; 154 cull->stage.reset_stipple_counter = cull_reset_stipple_counter; 155 cull->stage.destroy = cull_destroy; 156 157 if (!draw_alloc_temp_verts( &cull->stage, 0 )) 158 goto fail; 159 160 return &cull->stage; 161 162fail: 163 if (cull) 164 cull->stage.destroy( &cull->stage ); 165 166 return NULL; 167} 168