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