| /* |
| * Mesa 3-D graphics library |
| * |
| * Copyright 2008 VMware, Inc. |
| * Copyright (C) 2010 LunarG Inc. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included |
| * in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| * DEALINGS IN THE SOFTWARE. |
| * |
| * Authors: |
| * Keith Whitwell <keithw@vmware.com> |
| * Chia-I Wu <olv@lunarg.com> |
| */ |
| |
| /* these macros are optional */ |
| #ifndef LOCAL_VARS |
| #define LOCAL_VARS |
| #endif |
| #ifndef FUNC_ENTER |
| #define FUNC_ENTER do {} while (0) |
| #endif |
| #ifndef FUNC_EXIT |
| #define FUNC_EXIT do {} while (0) |
| #endif |
| #ifndef LINE_ADJ |
| #define LINE_ADJ(flags, a0, i0, i1, a1) LINE(flags, i0, i1) |
| #endif |
| #ifndef TRIANGLE_ADJ |
| #define TRIANGLE_ADJ(flags, i0, a0, i1, a1, i2, a2) TRIANGLE(flags, i0, i1, i2) |
| #endif |
| |
| static void |
| FUNC(FUNC_VARS) |
| { |
| unsigned idx[6], i; |
| ushort flags; |
| LOCAL_VARS |
| |
| FUNC_ENTER; |
| |
| /* prim, prim_flags, count, and last_vertex_last should have been defined */ |
| if (0) { |
| debug_printf("%s: prim 0x%x, prim_flags 0x%x, count %d, last_vertex_last %d\n", |
| __FUNCTION__, prim, prim_flags, count, last_vertex_last); |
| } |
| |
| switch (prim) { |
| case PIPE_PRIM_POINTS: |
| for (i = 0; i < count; i++) { |
| idx[0] = GET_ELT(i); |
| POINT(idx[0]); |
| } |
| break; |
| |
| case PIPE_PRIM_LINES: |
| flags = DRAW_PIPE_RESET_STIPPLE; |
| for (i = 0; i + 1 < count; i += 2) { |
| idx[0] = GET_ELT(i); |
| idx[1] = GET_ELT(i + 1); |
| LINE(flags, idx[0], idx[1]); |
| } |
| break; |
| |
| case PIPE_PRIM_LINE_LOOP: |
| case PIPE_PRIM_LINE_STRIP: |
| if (count >= 2) { |
| flags = (prim_flags & DRAW_SPLIT_BEFORE) ? 0 : DRAW_PIPE_RESET_STIPPLE; |
| idx[1] = GET_ELT(0); |
| idx[2] = idx[1]; |
| |
| for (i = 1; i < count; i++, flags = 0) { |
| idx[0] = idx[1]; |
| idx[1] = GET_ELT(i); |
| LINE(flags, idx[0], idx[1]); |
| } |
| /* close the loop */ |
| if (prim == PIPE_PRIM_LINE_LOOP && !prim_flags) |
| LINE(flags, idx[1], idx[2]); |
| } |
| break; |
| |
| case PIPE_PRIM_TRIANGLES: |
| flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL; |
| for (i = 0; i + 2 < count; i += 3) { |
| idx[0] = GET_ELT(i); |
| idx[1] = GET_ELT(i + 1); |
| idx[2] = GET_ELT(i + 2); |
| TRIANGLE(flags, idx[0], idx[1], idx[2]); |
| } |
| break; |
| |
| case PIPE_PRIM_TRIANGLE_STRIP: |
| if (count >= 3) { |
| flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL; |
| idx[1] = GET_ELT(0); |
| idx[2] = GET_ELT(1); |
| |
| if (last_vertex_last) { |
| for (i = 0; i + 2 < count; i++) { |
| idx[0] = idx[1]; |
| idx[1] = idx[2]; |
| idx[2] = GET_ELT(i + 2); |
| /* always emit idx[2] last */ |
| if (i & 1) |
| TRIANGLE(flags, idx[1], idx[0], idx[2]); |
| else |
| TRIANGLE(flags, idx[0], idx[1], idx[2]); |
| } |
| } |
| else { |
| for (i = 0; i + 2 < count; i++) { |
| idx[0] = idx[1]; |
| idx[1] = idx[2]; |
| idx[2] = GET_ELT(i + 2); |
| /* always emit idx[0] first */ |
| if (i & 1) |
| TRIANGLE(flags, idx[0], idx[2], idx[1]); |
| else |
| TRIANGLE(flags, idx[0], idx[1], idx[2]); |
| } |
| } |
| } |
| break; |
| |
| case PIPE_PRIM_TRIANGLE_FAN: |
| if (count >= 3) { |
| flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL; |
| idx[0] = GET_ELT(0); |
| idx[2] = GET_ELT(1); |
| |
| /* idx[0] is neither the first nor the last vertex */ |
| if (last_vertex_last) { |
| for (i = 0; i + 2 < count; i++) { |
| idx[1] = idx[2]; |
| idx[2] = GET_ELT(i + 2); |
| /* always emit idx[2] last */ |
| TRIANGLE(flags, idx[0], idx[1], idx[2]); |
| } |
| } |
| else { |
| for (i = 0; i + 2 < count; i++) { |
| idx[1] = idx[2]; |
| idx[2] = GET_ELT(i + 2); |
| /* always emit idx[1] first */ |
| TRIANGLE(flags, idx[1], idx[2], idx[0]); |
| } |
| } |
| } |
| break; |
| |
| case PIPE_PRIM_QUADS: |
| if (last_vertex_last) { |
| for (i = 0; i + 3 < count; i += 4) { |
| idx[0] = GET_ELT(i); |
| idx[1] = GET_ELT(i + 1); |
| idx[2] = GET_ELT(i + 2); |
| idx[3] = GET_ELT(i + 3); |
| #ifdef PASS_QUADS |
| QUAD(0, idx[0], idx[1], |
| idx[2], idx[3]); |
| #else |
| flags = DRAW_PIPE_RESET_STIPPLE | |
| DRAW_PIPE_EDGE_FLAG_0 | |
| DRAW_PIPE_EDGE_FLAG_2; |
| /* always emit idx[3] last */ |
| TRIANGLE(flags, idx[0], idx[1], idx[3]); |
| |
| flags = DRAW_PIPE_EDGE_FLAG_0 | |
| DRAW_PIPE_EDGE_FLAG_1; |
| TRIANGLE(flags, idx[1], idx[2], idx[3]); |
| #endif |
| } |
| } |
| else { |
| for (i = 0; i + 3 < count; i += 4) { |
| idx[0] = GET_ELT(i); |
| idx[1] = GET_ELT(i + 1); |
| idx[2] = GET_ELT(i + 2); |
| idx[3] = GET_ELT(i + 3); |
| #ifdef PASS_QUADS |
| QUAD(0, idx[0], idx[1], |
| idx[2], idx[3]); |
| #else |
| flags = DRAW_PIPE_RESET_STIPPLE | |
| DRAW_PIPE_EDGE_FLAG_0 | |
| DRAW_PIPE_EDGE_FLAG_1; |
| /* always emit idx[3] / idx[0] first */ |
| if (quads_flatshade_last) |
| TRIANGLE(flags, idx[3], idx[0], idx[1]); |
| else |
| TRIANGLE(flags, idx[0], idx[1], idx[2]); |
| |
| flags = DRAW_PIPE_EDGE_FLAG_1 | |
| DRAW_PIPE_EDGE_FLAG_2; |
| if (quads_flatshade_last) |
| TRIANGLE(flags, idx[3], idx[1], idx[2]); |
| else |
| TRIANGLE(flags, idx[0], idx[2], idx[3]); |
| #endif |
| } |
| } |
| break; |
| |
| case PIPE_PRIM_QUAD_STRIP: |
| if (count >= 4) { |
| idx[2] = GET_ELT(0); |
| idx[3] = GET_ELT(1); |
| |
| if (last_vertex_last) { |
| for (i = 0; i + 3 < count; i += 2) { |
| idx[0] = idx[2]; |
| idx[1] = idx[3]; |
| idx[2] = GET_ELT(i + 2); |
| idx[3] = GET_ELT(i + 3); |
| |
| #ifdef PASS_QUADS |
| QUAD(0, idx[2], idx[0], |
| idx[1], idx[3]); |
| #else |
| /* always emit idx[3] last */ |
| flags = DRAW_PIPE_RESET_STIPPLE | |
| DRAW_PIPE_EDGE_FLAG_0 | |
| DRAW_PIPE_EDGE_FLAG_2; |
| TRIANGLE(flags, idx[2], idx[0], idx[3]); |
| |
| flags = DRAW_PIPE_EDGE_FLAG_0 | |
| DRAW_PIPE_EDGE_FLAG_1; |
| TRIANGLE(flags, idx[0], idx[1], idx[3]); |
| #endif |
| } |
| } |
| else { |
| for (i = 0; i + 3 < count; i += 2) { |
| idx[0] = idx[2]; |
| idx[1] = idx[3]; |
| idx[2] = GET_ELT(i + 2); |
| idx[3] = GET_ELT(i + 3); |
| |
| #ifdef PASS_QUADS |
| QUAD(0, idx[3], idx[2], |
| idx[0], idx[1]); |
| #else |
| flags = DRAW_PIPE_RESET_STIPPLE | |
| DRAW_PIPE_EDGE_FLAG_0 | |
| DRAW_PIPE_EDGE_FLAG_1; |
| /* always emit idx[3] / idx[0 first */ |
| if (quads_flatshade_last) |
| TRIANGLE(flags, idx[3], idx[2], idx[0]); |
| else |
| TRIANGLE(flags, idx[0], idx[3], idx[2]); |
| |
| flags = DRAW_PIPE_EDGE_FLAG_1 | |
| DRAW_PIPE_EDGE_FLAG_2; |
| if (quads_flatshade_last) |
| TRIANGLE(flags, idx[3], idx[0], idx[1]); |
| else |
| TRIANGLE(flags, idx[0], idx[1], idx[3]); |
| #endif |
| } |
| } |
| } |
| break; |
| |
| case PIPE_PRIM_POLYGON: |
| if (count >= 3) { |
| ushort edge_next, edge_finish; |
| |
| if (last_vertex_last) { |
| flags = (DRAW_PIPE_RESET_STIPPLE | |
| DRAW_PIPE_EDGE_FLAG_0); |
| if (!(prim_flags & DRAW_SPLIT_BEFORE)) |
| flags |= DRAW_PIPE_EDGE_FLAG_2; |
| |
| edge_next = DRAW_PIPE_EDGE_FLAG_0; |
| edge_finish = |
| (prim_flags & DRAW_SPLIT_AFTER) ? 0 : DRAW_PIPE_EDGE_FLAG_1; |
| } |
| else { |
| flags = (DRAW_PIPE_RESET_STIPPLE | |
| DRAW_PIPE_EDGE_FLAG_1); |
| if (!(prim_flags & DRAW_SPLIT_BEFORE)) |
| flags |= DRAW_PIPE_EDGE_FLAG_0; |
| |
| edge_next = DRAW_PIPE_EDGE_FLAG_1; |
| edge_finish = |
| (prim_flags & DRAW_SPLIT_AFTER) ? 0 : DRAW_PIPE_EDGE_FLAG_2; |
| } |
| |
| idx[0] = GET_ELT(0); |
| idx[2] = GET_ELT(1); |
| |
| for (i = 0; i + 2 < count; i++, flags = edge_next) { |
| idx[1] = idx[2]; |
| idx[2] = GET_ELT(i + 2); |
| |
| if (i + 3 == count) |
| flags |= edge_finish; |
| |
| /* idx[0] is both the first and the last vertex */ |
| if (last_vertex_last) |
| TRIANGLE(flags, idx[1], idx[2], idx[0]); |
| else |
| TRIANGLE(flags, idx[0], idx[1], idx[2]); |
| } |
| } |
| break; |
| |
| case PIPE_PRIM_LINES_ADJACENCY: |
| flags = DRAW_PIPE_RESET_STIPPLE; |
| for (i = 0; i + 3 < count; i += 4) { |
| idx[0] = GET_ELT(i); |
| idx[1] = GET_ELT(i + 1); |
| idx[2] = GET_ELT(i + 2); |
| idx[3] = GET_ELT(i + 3); |
| LINE_ADJ(flags, idx[0], idx[1], idx[2], idx[3]); |
| } |
| break; |
| |
| case PIPE_PRIM_LINE_STRIP_ADJACENCY: |
| if (count >= 4) { |
| flags = (prim_flags & DRAW_SPLIT_BEFORE) ? 0 : DRAW_PIPE_RESET_STIPPLE; |
| idx[1] = GET_ELT(0); |
| idx[2] = GET_ELT(1); |
| idx[3] = GET_ELT(2); |
| |
| for (i = 1; i + 2 < count; i++, flags = 0) { |
| idx[0] = idx[1]; |
| idx[1] = idx[2]; |
| idx[2] = idx[3]; |
| idx[3] = GET_ELT(i + 2); |
| LINE_ADJ(flags, idx[0], idx[1], idx[2], idx[3]); |
| } |
| } |
| break; |
| |
| case PIPE_PRIM_TRIANGLES_ADJACENCY: |
| flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL; |
| for (i = 0; i + 5 < count; i += 6) { |
| idx[0] = GET_ELT(i); |
| idx[1] = GET_ELT(i + 1); |
| idx[2] = GET_ELT(i + 2); |
| idx[3] = GET_ELT(i + 3); |
| idx[4] = GET_ELT(i + 4); |
| idx[5] = GET_ELT(i + 5); |
| TRIANGLE_ADJ(flags, idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]); |
| } |
| break; |
| |
| case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: |
| if (count >= 6) { |
| flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL; |
| idx[0] = GET_ELT(1); |
| idx[2] = GET_ELT(0); |
| idx[4] = GET_ELT(2); |
| idx[3] = GET_ELT(4); |
| |
| /* |
| * The vertices of the i-th triangle are stored in |
| * idx[0,2,4] = { 2*i, 2*i+2, 2*i+4 }; |
| * |
| * The adjacent vertices are stored in |
| * idx[1,3,5] = { 2*i-2, 2*i+6, 2*i+3 }. |
| * |
| * However, there are two exceptions: |
| * |
| * For the first triangle, idx[1] = 1; |
| * For the last triangle, idx[3] = 2*i+5. |
| */ |
| if (last_vertex_last) { |
| for (i = 0; i + 5 < count; i += 2) { |
| idx[1] = idx[0]; |
| |
| idx[0] = idx[2]; |
| idx[2] = idx[4]; |
| idx[4] = idx[3]; |
| |
| idx[3] = GET_ELT(i + ((i + 7 < count) ? 6 : 5)); |
| idx[5] = GET_ELT(i + 3); |
| |
| /* |
| * alternate the first two vertices (idx[0] and idx[2]) and the |
| * corresponding adjacent vertices (idx[3] and idx[5]) to have |
| * the correct orientation |
| */ |
| if (i & 2) { |
| TRIANGLE_ADJ(flags, |
| idx[2], idx[1], idx[0], idx[5], idx[4], idx[3]); |
| } |
| else { |
| TRIANGLE_ADJ(flags, |
| idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]); |
| } |
| } |
| } |
| else { |
| for (i = 0; i + 5 < count; i += 2) { |
| idx[1] = idx[0]; |
| |
| idx[0] = idx[2]; |
| idx[2] = idx[4]; |
| idx[4] = idx[3]; |
| |
| idx[3] = GET_ELT(i + ((i + 7 < count) ? 6 : 5)); |
| idx[5] = GET_ELT(i + 3); |
| |
| /* |
| * alternate the last two vertices (idx[2] and idx[4]) and the |
| * corresponding adjacent vertices (idx[1] and idx[5]) to have |
| * the correct orientation |
| */ |
| if (i & 2) { |
| TRIANGLE_ADJ(flags, |
| idx[0], idx[5], idx[4], idx[3], idx[2], idx[1]); |
| } |
| else { |
| TRIANGLE_ADJ(flags, |
| idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]); |
| } |
| } |
| } |
| } |
| break; |
| |
| default: |
| assert(0); |
| break; |
| } |
| |
| FUNC_EXIT; |
| } |
| |
| #undef LOCAL_VARS |
| #undef FUNC_ENTER |
| #undef FUNC_EXIT |
| #undef LINE_ADJ |
| #undef TRIANGLE_ADJ |
| |
| #undef FUNC |
| #undef FUNC_VARS |
| #undef GET_ELT |
| #undef POINT |
| #undef LINE |
| #undef TRIANGLE |