Home | History | Annotate | Download | only in draw
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright 2008 VMware, Inc.
      5  * Copyright (C) 2010 LunarG Inc.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the "Software"),
      9  * to deal in the Software without restriction, including without limitation
     10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11  * and/or sell copies of the Software, and to permit persons to whom the
     12  * Software is furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included
     15  * in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     23  * DEALINGS IN THE SOFTWARE.
     24  *
     25  * Authors:
     26   *   Keith Whitwell <keithw (at) vmware.com>
     27  *    Chia-I Wu <olv (at) lunarg.com>
     28  */
     29 
     30 /* these macros are optional */
     31 #ifndef LOCAL_VARS
     32 #define LOCAL_VARS
     33 #endif
     34 #ifndef FUNC_ENTER
     35 #define FUNC_ENTER do {} while (0)
     36 #endif
     37 #ifndef FUNC_EXIT
     38 #define FUNC_EXIT do {} while (0)
     39 #endif
     40 #ifndef LINE_ADJ
     41 #define LINE_ADJ(flags, a0, i0, i1, a1) LINE(flags, i0, i1)
     42 #endif
     43 #ifndef TRIANGLE_ADJ
     44 #define TRIANGLE_ADJ(flags, i0, a0, i1, a1, i2, a2) TRIANGLE(flags, i0, i1, i2)
     45 #endif
     46 
     47 static void
     48 FUNC(FUNC_VARS)
     49 {
     50    unsigned idx[6], i;
     51    ushort flags;
     52    LOCAL_VARS
     53 
     54    FUNC_ENTER;
     55 
     56    /* prim, prim_flags, count, and last_vertex_last should have been defined */
     57    if (0) {
     58       debug_printf("%s: prim 0x%x, prim_flags 0x%x, count %d, last_vertex_last %d\n",
     59             __FUNCTION__, prim, prim_flags, count, last_vertex_last);
     60    }
     61 
     62    switch (prim) {
     63    case PIPE_PRIM_POINTS:
     64       for (i = 0; i < count; i++) {
     65          idx[0] = GET_ELT(i);
     66          POINT(idx[0]);
     67       }
     68       break;
     69 
     70    case PIPE_PRIM_LINES:
     71       flags = DRAW_PIPE_RESET_STIPPLE;
     72       for (i = 0; i + 1 < count; i += 2) {
     73          idx[0] = GET_ELT(i);
     74          idx[1] = GET_ELT(i + 1);
     75          LINE(flags, idx[0], idx[1]);
     76       }
     77       break;
     78 
     79    case PIPE_PRIM_LINE_LOOP:
     80    case PIPE_PRIM_LINE_STRIP:
     81       if (count >= 2) {
     82          flags = (prim_flags & DRAW_SPLIT_BEFORE) ? 0 : DRAW_PIPE_RESET_STIPPLE;
     83          idx[1] = GET_ELT(0);
     84          idx[2] = idx[1];
     85 
     86          for (i = 1; i < count; i++, flags = 0) {
     87             idx[0] = idx[1];
     88             idx[1] = GET_ELT(i);
     89             LINE(flags, idx[0], idx[1]);
     90          }
     91          /* close the loop */
     92          if (prim == PIPE_PRIM_LINE_LOOP && !prim_flags)
     93             LINE(flags, idx[1], idx[2]);
     94       }
     95       break;
     96 
     97    case PIPE_PRIM_TRIANGLES:
     98       flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
     99       for (i = 0; i + 2 < count; i += 3) {
    100          idx[0] = GET_ELT(i);
    101          idx[1] = GET_ELT(i + 1);
    102          idx[2] = GET_ELT(i + 2);
    103          TRIANGLE(flags, idx[0], idx[1], idx[2]);
    104       }
    105       break;
    106 
    107    case PIPE_PRIM_TRIANGLE_STRIP:
    108       if (count >= 3) {
    109          flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
    110          idx[1] = GET_ELT(0);
    111          idx[2] = GET_ELT(1);
    112 
    113          if (last_vertex_last) {
    114             for (i = 0; i + 2 < count; i++) {
    115                idx[0] = idx[1];
    116                idx[1] = idx[2];
    117                idx[2] = GET_ELT(i + 2);
    118                /* always emit idx[2] last */
    119                if (i & 1)
    120                   TRIANGLE(flags, idx[1], idx[0], idx[2]);
    121                else
    122                   TRIANGLE(flags, idx[0], idx[1], idx[2]);
    123             }
    124          }
    125          else {
    126             for (i = 0; i + 2 < count; i++) {
    127                idx[0] = idx[1];
    128                idx[1] = idx[2];
    129                idx[2] = GET_ELT(i + 2);
    130                /* always emit idx[0] first */
    131                if (i & 1)
    132                   TRIANGLE(flags, idx[0], idx[2], idx[1]);
    133                else
    134                   TRIANGLE(flags, idx[0], idx[1], idx[2]);
    135             }
    136          }
    137       }
    138       break;
    139 
    140    case PIPE_PRIM_TRIANGLE_FAN:
    141       if (count >= 3) {
    142          flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
    143          idx[0] = GET_ELT(0);
    144          idx[2] = GET_ELT(1);
    145 
    146          /* idx[0] is neither the first nor the last vertex */
    147          if (last_vertex_last) {
    148             for (i = 0; i + 2 < count; i++) {
    149                idx[1] = idx[2];
    150                idx[2] = GET_ELT(i + 2);
    151                /* always emit idx[2] last */
    152                TRIANGLE(flags, idx[0], idx[1], idx[2]);
    153             }
    154          }
    155          else {
    156             for (i = 0; i + 2 < count; i++) {
    157                idx[1] = idx[2];
    158                idx[2] = GET_ELT(i + 2);
    159                /* always emit idx[1] first */
    160                TRIANGLE(flags, idx[1], idx[2], idx[0]);
    161             }
    162          }
    163       }
    164       break;
    165 
    166    case PIPE_PRIM_QUADS:
    167       if (last_vertex_last) {
    168          for (i = 0; i + 3 < count; i += 4) {
    169             idx[0] = GET_ELT(i);
    170             idx[1] = GET_ELT(i + 1);
    171             idx[2] = GET_ELT(i + 2);
    172             idx[3] = GET_ELT(i + 3);
    173 
    174             flags = DRAW_PIPE_RESET_STIPPLE |
    175                     DRAW_PIPE_EDGE_FLAG_0 |
    176                     DRAW_PIPE_EDGE_FLAG_2;
    177             /* always emit idx[3] last */
    178             TRIANGLE(flags, idx[0], idx[1], idx[3]);
    179 
    180             flags = DRAW_PIPE_EDGE_FLAG_0 |
    181                     DRAW_PIPE_EDGE_FLAG_1;
    182             TRIANGLE(flags, idx[1], idx[2], idx[3]);
    183          }
    184       }
    185       else {
    186          for (i = 0; i + 3 < count; i += 4) {
    187             idx[0] = GET_ELT(i);
    188             idx[1] = GET_ELT(i + 1);
    189             idx[2] = GET_ELT(i + 2);
    190             idx[3] = GET_ELT(i + 3);
    191 
    192             flags = DRAW_PIPE_RESET_STIPPLE |
    193                     DRAW_PIPE_EDGE_FLAG_0 |
    194                     DRAW_PIPE_EDGE_FLAG_1;
    195             /* always emit idx[3] / idx[0] first */
    196             if (quads_flatshade_last)
    197                TRIANGLE(flags, idx[3], idx[0], idx[1]);
    198             else
    199                TRIANGLE(flags, idx[0], idx[1], idx[2]);
    200 
    201             flags = DRAW_PIPE_EDGE_FLAG_1 |
    202                     DRAW_PIPE_EDGE_FLAG_2;
    203             if (quads_flatshade_last)
    204                TRIANGLE(flags, idx[3], idx[1], idx[2]);
    205             else
    206                TRIANGLE(flags, idx[0], idx[2], idx[3]);
    207          }
    208       }
    209       break;
    210 
    211    case PIPE_PRIM_QUAD_STRIP:
    212       if (count >= 4) {
    213          idx[2] = GET_ELT(0);
    214          idx[3] = GET_ELT(1);
    215 
    216          if (last_vertex_last) {
    217             for (i = 0; i + 3 < count; i += 2) {
    218                idx[0] = idx[2];
    219                idx[1] = idx[3];
    220                idx[2] = GET_ELT(i + 2);
    221                idx[3] = GET_ELT(i + 3);
    222 
    223                /* always emit idx[3] last */
    224                flags = DRAW_PIPE_RESET_STIPPLE |
    225                        DRAW_PIPE_EDGE_FLAG_0 |
    226                        DRAW_PIPE_EDGE_FLAG_2;
    227                TRIANGLE(flags, idx[2], idx[0], idx[3]);
    228 
    229                flags = DRAW_PIPE_EDGE_FLAG_0 |
    230                        DRAW_PIPE_EDGE_FLAG_1;
    231                TRIANGLE(flags, idx[0], idx[1], idx[3]);
    232             }
    233          }
    234          else {
    235             for (i = 0; i + 3 < count; i += 2) {
    236                idx[0] = idx[2];
    237                idx[1] = idx[3];
    238                idx[2] = GET_ELT(i + 2);
    239                idx[3] = GET_ELT(i + 3);
    240 
    241                flags = DRAW_PIPE_RESET_STIPPLE |
    242                        DRAW_PIPE_EDGE_FLAG_0 |
    243                        DRAW_PIPE_EDGE_FLAG_1;
    244                /* always emit idx[3] / idx[0 first */
    245                if (quads_flatshade_last)
    246                   TRIANGLE(flags, idx[3], idx[2], idx[0]);
    247                else
    248                   TRIANGLE(flags, idx[0], idx[3], idx[2]);
    249 
    250                flags = DRAW_PIPE_EDGE_FLAG_1 |
    251                        DRAW_PIPE_EDGE_FLAG_2;
    252                if (quads_flatshade_last)
    253                   TRIANGLE(flags, idx[3], idx[0], idx[1]);
    254                else
    255                   TRIANGLE(flags, idx[0], idx[1], idx[3]);
    256             }
    257          }
    258       }
    259       break;
    260 
    261    case PIPE_PRIM_POLYGON:
    262       if (count >= 3) {
    263          ushort edge_next, edge_finish;
    264 
    265          if (last_vertex_last) {
    266             flags = (DRAW_PIPE_RESET_STIPPLE |
    267                      DRAW_PIPE_EDGE_FLAG_0);
    268             if (!(prim_flags & DRAW_SPLIT_BEFORE))
    269                flags |= DRAW_PIPE_EDGE_FLAG_2;
    270 
    271             edge_next = DRAW_PIPE_EDGE_FLAG_0;
    272             edge_finish =
    273                (prim_flags & DRAW_SPLIT_AFTER) ? 0 : DRAW_PIPE_EDGE_FLAG_1;
    274          }
    275          else {
    276             flags = (DRAW_PIPE_RESET_STIPPLE |
    277                      DRAW_PIPE_EDGE_FLAG_1);
    278             if (!(prim_flags & DRAW_SPLIT_BEFORE))
    279                flags |= DRAW_PIPE_EDGE_FLAG_0;
    280 
    281             edge_next = DRAW_PIPE_EDGE_FLAG_1;
    282             edge_finish =
    283                (prim_flags & DRAW_SPLIT_AFTER) ? 0 : DRAW_PIPE_EDGE_FLAG_2;
    284          }
    285 
    286          idx[0] = GET_ELT(0);
    287          idx[2] = GET_ELT(1);
    288 
    289          for (i = 0; i + 2 < count; i++, flags = edge_next) {
    290             idx[1] = idx[2];
    291             idx[2] = GET_ELT(i + 2);
    292 
    293             if (i + 3 == count)
    294                flags |= edge_finish;
    295 
    296             /* idx[0] is both the first and the last vertex */
    297             if (last_vertex_last)
    298                TRIANGLE(flags, idx[1], idx[2], idx[0]);
    299             else
    300                TRIANGLE(flags, idx[0], idx[1], idx[2]);
    301          }
    302       }
    303       break;
    304 
    305    case PIPE_PRIM_LINES_ADJACENCY:
    306       flags = DRAW_PIPE_RESET_STIPPLE;
    307       for (i = 0; i + 3 < count; i += 4) {
    308          idx[0] = GET_ELT(i);
    309          idx[1] = GET_ELT(i + 1);
    310          idx[2] = GET_ELT(i + 2);
    311          idx[3] = GET_ELT(i + 3);
    312          LINE_ADJ(flags, idx[0], idx[1], idx[2], idx[3]);
    313       }
    314       break;
    315 
    316    case PIPE_PRIM_LINE_STRIP_ADJACENCY:
    317       if (count >= 4) {
    318          flags = (prim_flags & DRAW_SPLIT_BEFORE) ? 0 : DRAW_PIPE_RESET_STIPPLE;
    319          idx[1] = GET_ELT(0);
    320          idx[2] = GET_ELT(1);
    321          idx[3] = GET_ELT(2);
    322 
    323          for (i = 1; i + 2 < count; i++, flags = 0) {
    324             idx[0] = idx[1];
    325             idx[1] = idx[2];
    326             idx[2] = idx[3];
    327             idx[3] = GET_ELT(i + 2);
    328             LINE_ADJ(flags, idx[0], idx[1], idx[2], idx[3]);
    329          }
    330       }
    331       break;
    332 
    333    case PIPE_PRIM_TRIANGLES_ADJACENCY:
    334       flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
    335       for (i = 0; i + 5 < count; i += 6) {
    336          idx[0] = GET_ELT(i);
    337          idx[1] = GET_ELT(i + 1);
    338          idx[2] = GET_ELT(i + 2);
    339          idx[3] = GET_ELT(i + 3);
    340          idx[4] = GET_ELT(i + 4);
    341          idx[5] = GET_ELT(i + 5);
    342          TRIANGLE_ADJ(flags, idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]);
    343       }
    344       break;
    345 
    346    case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
    347       if (count >= 6) {
    348          flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
    349          idx[0] = GET_ELT(1);
    350          idx[2] = GET_ELT(0);
    351          idx[4] = GET_ELT(2);
    352          idx[3] = GET_ELT(4);
    353 
    354          /*
    355           * The vertices of the i-th triangle are stored in
    356           * idx[0,2,4] = { 2*i, 2*i+2, 2*i+4 };
    357           *
    358           * The adjacent vertices are stored in
    359           * idx[1,3,5] = { 2*i-2, 2*i+6, 2*i+3 }.
    360           *
    361           * However, there are two exceptions:
    362           *
    363           * For the first triangle, idx[1] = 1;
    364           * For the  last triangle, idx[3] = 2*i+5.
    365           */
    366          if (last_vertex_last) {
    367             for (i = 0; i + 5 < count; i += 2) {
    368                idx[1] = idx[0];
    369 
    370                idx[0] = idx[2];
    371                idx[2] = idx[4];
    372                idx[4] = idx[3];
    373 
    374                idx[3] = GET_ELT(i + ((i + 7 < count) ? 6 : 5));
    375                idx[5] = GET_ELT(i + 3);
    376 
    377                /*
    378                 * alternate the first two vertices (idx[0] and idx[2]) and the
    379                 * corresponding adjacent vertices (idx[3] and idx[5]) to have
    380                 * the correct orientation
    381                 */
    382                if (i & 2) {
    383                   TRIANGLE_ADJ(flags,
    384                         idx[2], idx[1], idx[0], idx[5], idx[4], idx[3]);
    385                }
    386                else {
    387                   TRIANGLE_ADJ(flags,
    388                         idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]);
    389                }
    390             }
    391          }
    392          else {
    393             for (i = 0; i + 5 < count; i += 2) {
    394                idx[1] = idx[0];
    395 
    396                idx[0] = idx[2];
    397                idx[2] = idx[4];
    398                idx[4] = idx[3];
    399 
    400                idx[3] = GET_ELT(i + ((i + 7 < count) ? 6 : 5));
    401                idx[5] = GET_ELT(i + 3);
    402 
    403                /*
    404                 * alternate the last two vertices (idx[2] and idx[4]) and the
    405                 * corresponding adjacent vertices (idx[1] and idx[5]) to have
    406                 * the correct orientation
    407                 */
    408                if (i & 2) {
    409                   TRIANGLE_ADJ(flags,
    410                         idx[0], idx[5], idx[4], idx[3], idx[2], idx[1]);
    411                }
    412                else {
    413                   TRIANGLE_ADJ(flags,
    414                         idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]);
    415                }
    416             }
    417          }
    418       }
    419       break;
    420 
    421    default:
    422       assert(0);
    423       break;
    424    }
    425 
    426    FUNC_EXIT;
    427 }
    428 
    429 #undef LOCAL_VARS
    430 #undef FUNC_ENTER
    431 #undef FUNC_EXIT
    432 #undef LINE_ADJ
    433 #undef TRIANGLE_ADJ
    434 
    435 #undef FUNC
    436 #undef FUNC_VARS
    437 #undef GET_ELT
    438 #undef POINT
    439 #undef LINE
    440 #undef TRIANGLE
    441