Home | History | Annotate | Download | only in draw
      1 /**************************************************************************
      2  *
      3  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
      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 TUNGSTEN GRAPHICS 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  polygon offset state
     30  *
     31  * \author  Keith Whitwell <keith (at) tungstengraphics.com>
     32  * \author  Brian Paul
     33  */
     34 
     35 #include "util/u_math.h"
     36 #include "util/u_memory.h"
     37 #include "draw_pipe.h"
     38 
     39 
     40 
     41 struct offset_stage {
     42    struct draw_stage stage;
     43 
     44    float scale;
     45    float units;
     46    float clamp;
     47 };
     48 
     49 
     50 
     51 static INLINE struct offset_stage *offset_stage( struct draw_stage *stage )
     52 {
     53    return (struct offset_stage *) stage;
     54 }
     55 
     56 
     57 
     58 
     59 
     60 /**
     61  * Offset tri Z.  Some hardware can handle this, but not usually when
     62  * doing unfilled rendering.
     63  */
     64 static void do_offset_tri( struct draw_stage *stage,
     65 			   struct prim_header *header )
     66 {
     67    const unsigned pos = draw_current_shader_position_output(stage->draw);
     68    struct offset_stage *offset = offset_stage(stage);
     69    float inv_det = 1.0f / header->det;
     70 
     71    /* Window coords:
     72     */
     73    float *v0 = header->v[0]->data[pos];
     74    float *v1 = header->v[1]->data[pos];
     75    float *v2 = header->v[2]->data[pos];
     76 
     77    /* edge vectors e = v0 - v2, f = v1 - v2 */
     78    float ex = v0[0] - v2[0];
     79    float ey = v0[1] - v2[1];
     80    float ez = v0[2] - v2[2];
     81    float fx = v1[0] - v2[0];
     82    float fy = v1[1] - v2[1];
     83    float fz = v1[2] - v2[2];
     84 
     85    /* (a,b) = cross(e,f).xy */
     86    float a = ey*fz - ez*fy;
     87    float b = ez*fx - ex*fz;
     88 
     89    float dzdx = fabsf(a * inv_det);
     90    float dzdy = fabsf(b * inv_det);
     91 
     92    float zoffset = offset->units + MAX2(dzdx, dzdy) * offset->scale;
     93 
     94    if (offset->clamp)
     95       zoffset = (offset->clamp < 0.0f) ? MAX2(zoffset, offset->clamp) :
     96                                          MIN2(zoffset, offset->clamp);
     97 
     98    /*
     99     * Note: we're applying the offset and clamping per-vertex.
    100     * Ideally, the offset is applied per-fragment prior to fragment shading.
    101     */
    102    v0[2] = CLAMP(v0[2] + zoffset, 0.0f, 1.0f);
    103    v1[2] = CLAMP(v1[2] + zoffset, 0.0f, 1.0f);
    104    v2[2] = CLAMP(v2[2] + zoffset, 0.0f, 1.0f);
    105 
    106    stage->next->tri( stage->next, header );
    107 }
    108 
    109 
    110 static void offset_tri( struct draw_stage *stage,
    111 			struct prim_header *header )
    112 {
    113    struct prim_header tmp;
    114 
    115    tmp.det = header->det;
    116    tmp.flags = header->flags;
    117    tmp.pad = header->pad;
    118    tmp.v[0] = dup_vert(stage, header->v[0], 0);
    119    tmp.v[1] = dup_vert(stage, header->v[1], 1);
    120    tmp.v[2] = dup_vert(stage, header->v[2], 2);
    121 
    122    do_offset_tri( stage, &tmp );
    123 }
    124 
    125 
    126 static void offset_first_tri( struct draw_stage *stage,
    127 			      struct prim_header *header )
    128 {
    129    struct offset_stage *offset = offset_stage(stage);
    130 
    131    offset->units = (float) (stage->draw->rasterizer->offset_units * stage->draw->mrd);
    132    offset->scale = stage->draw->rasterizer->offset_scale;
    133    offset->clamp = stage->draw->rasterizer->offset_clamp;
    134 
    135    stage->tri = offset_tri;
    136    stage->tri( stage, header );
    137 }
    138 
    139 
    140 
    141 
    142 static void offset_flush( struct draw_stage *stage,
    143 			  unsigned flags )
    144 {
    145    stage->tri = offset_first_tri;
    146    stage->next->flush( stage->next, flags );
    147 }
    148 
    149 
    150 static void offset_reset_stipple_counter( struct draw_stage *stage )
    151 {
    152    stage->next->reset_stipple_counter( stage->next );
    153 }
    154 
    155 
    156 static void offset_destroy( struct draw_stage *stage )
    157 {
    158    draw_free_temp_verts( stage );
    159    FREE( stage );
    160 }
    161 
    162 
    163 /**
    164  * Create polygon offset drawing stage.
    165  */
    166 struct draw_stage *draw_offset_stage( struct draw_context *draw )
    167 {
    168    struct offset_stage *offset = CALLOC_STRUCT(offset_stage);
    169    if (offset == NULL)
    170       goto fail;
    171 
    172    offset->stage.draw = draw;
    173    offset->stage.name = "offset";
    174    offset->stage.next = NULL;
    175    offset->stage.point = draw_pipe_passthrough_point;
    176    offset->stage.line = draw_pipe_passthrough_line;
    177    offset->stage.tri = offset_first_tri;
    178    offset->stage.flush = offset_flush;
    179    offset->stage.reset_stipple_counter = offset_reset_stipple_counter;
    180    offset->stage.destroy = offset_destroy;
    181 
    182    if (!draw_alloc_temp_verts( &offset->stage, 3 ))
    183       goto fail;
    184 
    185    return &offset->stage;
    186 
    187 fail:
    188    if (offset)
    189       offset->stage.destroy( &offset->stage );
    190 
    191    return NULL;
    192 }
    193