Home | History | Annotate | Download | only in draw
      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 /* Authors:  Keith Whitwell <keithw (at) vmware.com>
     29  */
     30 
     31 #include "pipe/p_context.h"
     32 #include "pipe/p_defines.h"
     33 #include "pipe/p_shader_tokens.h"
     34 #include "util/u_math.h"
     35 #include "util/u_memory.h"
     36 #include "draw_private.h"
     37 #include "draw_pipe.h"
     38 
     39 
     40 struct wideline_stage {
     41    struct draw_stage stage;
     42 
     43    float half_line_width;
     44 };
     45 
     46 
     47 
     48 static inline struct wideline_stage *wideline_stage( struct draw_stage *stage )
     49 {
     50    return (struct wideline_stage *)stage;
     51 }
     52 
     53 
     54 
     55 /**
     56  * Draw a wide line by drawing a quad (two triangles).
     57  */
     58 static void wideline_line( struct draw_stage *stage,
     59                            struct prim_header *header )
     60 {
     61    /*const struct wideline_stage *wide = wideline_stage(stage);*/
     62    const unsigned pos = draw_current_shader_position_output(stage->draw);
     63    const float half_width = 0.5f * stage->draw->rasterizer->line_width;
     64 
     65    struct prim_header tri;
     66 
     67    struct vertex_header *v0 = dup_vert(stage, header->v[0], 0);
     68    struct vertex_header *v1 = dup_vert(stage, header->v[0], 1);
     69    struct vertex_header *v2 = dup_vert(stage, header->v[1], 2);
     70    struct vertex_header *v3 = dup_vert(stage, header->v[1], 3);
     71 
     72    float *pos0 = v0->data[pos];
     73    float *pos1 = v1->data[pos];
     74    float *pos2 = v2->data[pos];
     75    float *pos3 = v3->data[pos];
     76 
     77    const float dx = fabsf(pos0[0] - pos2[0]);
     78    const float dy = fabsf(pos0[1] - pos2[1]);
     79 
     80    const boolean half_pixel_center =
     81       stage->draw->rasterizer->half_pixel_center;
     82 
     83    /* small tweak to meet GL specification */
     84    const float bias = half_pixel_center ? 0.125f : 0.0f;
     85 
     86    /*
     87     * Draw wide line as a quad (two tris) by "stretching" the line along
     88     * X or Y.
     89     * We need to tweak coords in several ways to be conformant here.
     90     */
     91 
     92    if (dx > dy) {
     93       /* x-major line */
     94       pos0[1] = pos0[1] - half_width - bias;
     95       pos1[1] = pos1[1] + half_width - bias;
     96       pos2[1] = pos2[1] - half_width - bias;
     97       pos3[1] = pos3[1] + half_width - bias;
     98       if (half_pixel_center) {
     99          if (pos0[0] < pos2[0]) {
    100             /* left to right line */
    101             pos0[0] -= 0.5f;
    102             pos1[0] -= 0.5f;
    103             pos2[0] -= 0.5f;
    104             pos3[0] -= 0.5f;
    105          }
    106          else {
    107             /* right to left line */
    108             pos0[0] += 0.5f;
    109             pos1[0] += 0.5f;
    110             pos2[0] += 0.5f;
    111             pos3[0] += 0.5f;
    112          }
    113       }
    114    }
    115    else {
    116       /* y-major line */
    117       pos0[0] = pos0[0] - half_width + bias;
    118       pos1[0] = pos1[0] + half_width + bias;
    119       pos2[0] = pos2[0] - half_width + bias;
    120       pos3[0] = pos3[0] + half_width + bias;
    121       if (half_pixel_center) {
    122          if (pos0[1] < pos2[1]) {
    123             /* top to bottom line */
    124             pos0[1] -= 0.5f;
    125             pos1[1] -= 0.5f;
    126             pos2[1] -= 0.5f;
    127             pos3[1] -= 0.5f;
    128          }
    129          else {
    130             /* bottom to top line */
    131             pos0[1] += 0.5f;
    132             pos1[1] += 0.5f;
    133             pos2[1] += 0.5f;
    134             pos3[1] += 0.5f;
    135          }
    136       }
    137    }
    138 
    139    tri.det = header->det;  /* only the sign matters */
    140    tri.v[0] = v0;
    141    tri.v[1] = v2;
    142    tri.v[2] = v3;
    143    stage->next->tri( stage->next, &tri );
    144 
    145    tri.v[0] = v0;
    146    tri.v[1] = v3;
    147    tri.v[2] = v1;
    148    stage->next->tri( stage->next, &tri );
    149 }
    150 
    151 
    152 static void wideline_first_line( struct draw_stage *stage,
    153                                  struct prim_header *header )
    154 {
    155    struct draw_context *draw = stage->draw;
    156    struct pipe_context *pipe = draw->pipe;
    157    const struct pipe_rasterizer_state *rast = draw->rasterizer;
    158    void *r;
    159 
    160    /* Disable triangle culling, stippling, unfilled mode etc. */
    161    r = draw_get_rasterizer_no_cull(draw, rast->scissor, rast->flatshade);
    162    draw->suspend_flushing = TRUE;
    163    pipe->bind_rasterizer_state(pipe, r);
    164    draw->suspend_flushing = FALSE;
    165 
    166    stage->line = wideline_line;
    167 
    168    wideline_line(stage, header);
    169 }
    170 
    171 
    172 static void wideline_flush( struct draw_stage *stage, unsigned flags )
    173 {
    174    struct draw_context *draw = stage->draw;
    175    struct pipe_context *pipe = draw->pipe;
    176 
    177    stage->line = wideline_first_line;
    178    stage->next->flush( stage->next, flags );
    179 
    180    /* restore original rasterizer state */
    181    if (draw->rast_handle) {
    182       draw->suspend_flushing = TRUE;
    183       pipe->bind_rasterizer_state(pipe, draw->rast_handle);
    184       draw->suspend_flushing = FALSE;
    185    }
    186 }
    187 
    188 
    189 static void wideline_reset_stipple_counter( struct draw_stage *stage )
    190 {
    191    stage->next->reset_stipple_counter( stage->next );
    192 }
    193 
    194 
    195 static void wideline_destroy( struct draw_stage *stage )
    196 {
    197    draw_free_temp_verts( stage );
    198    FREE( stage );
    199 }
    200 
    201 
    202 struct draw_stage *draw_wide_line_stage( struct draw_context *draw )
    203 {
    204    struct wideline_stage *wide = CALLOC_STRUCT(wideline_stage);
    205    if (!wide)
    206       goto fail;
    207 
    208    wide->stage.draw = draw;
    209    wide->stage.name = "wide-line";
    210    wide->stage.next = NULL;
    211    wide->stage.point = draw_pipe_passthrough_point;
    212    wide->stage.line = wideline_first_line;
    213    wide->stage.tri = draw_pipe_passthrough_tri;
    214    wide->stage.flush = wideline_flush;
    215    wide->stage.reset_stipple_counter = wideline_reset_stipple_counter;
    216    wide->stage.destroy = wideline_destroy;
    217 
    218    if (!draw_alloc_temp_verts( &wide->stage, 4 ))
    219       goto fail;
    220 
    221    return &wide->stage;
    222 
    223 fail:
    224    if (wide)
    225       wide->stage.destroy( &wide->stage );
    226 
    227    return NULL;
    228 }
    229