/* \brief return tristripped indecies for triangle index data */ glhckImportIndexData* _glhckTriStrip(const glhckImportIndexData *indices, unsigned int memb, unsigned int *outMemb) { #if !GLHCK_TRISTRIP (void)indices; (void)memb; (void)outMemb; /* stripping is disabled. * importers should fallback to GLHCK_TRIANGLES */ return NULL; #else int prim; glhckImportIndexData v1, v2, v3; glhckImportIndexData *outIndices = NULL, *newIndices = NULL; unsigned int i, primCount, tmp; ACTCData *tc = NULL; CALL(0, "%p, %u, %p", indices, memb, outMemb); /* check if the triangles we got are valid */ if (memb % 3 != 0) goto not_valid; if (!(outIndices = _glhckMalloc(memb * sizeof(glhckImportIndexData)))) goto out_of_memory; if (!(tc = actcNew())) goto actc_fail; /* parameters */ ACTC_CALL(actcParami(tc, ACTC_OUT_MIN_FAN_VERTS, INT_MAX)); ACTC_CALL(actcParami(tc, ACTC_OUT_HONOR_WINDING, ACTC_FALSE)); /* input data */ ACTC_CALL(actcBeginInput(tc)); for (i = 0; i != memb; i+=3) { ACTC_CALL(actcAddTriangle(tc, indices[i+0], indices[i+1], indices[i+2])); } ACTC_CALL(actcEndInput(tc)); /* FIXME: fix the winding of generated stiched strips */ /* output data */ tmp = memb, i = 0, primCount = 0; unsigned int flipStart = 0, length = 0; ACTC_CALL(actcBeginOutput(tc)); while ((prim = actcStartNextPrim(tc, &v1, &v2)) != ACTC_DATABASE_EMPTY) { assert(prim == ACTC_PRIM_STRIP); if (i + (primCount?5:3) > memb) goto no_profit; /* degenerate to next strip */ if (primCount && v1 != v3) { if (length & 1) { _glhckTriStripReverse(&outIndices[flipStart], i-flipStart); if (flipStart) outIndices[flipStart-1] = outIndices[flipStart]; } v3 = outIndices[i-1]; if (v1 != v3) { outIndices[i++] = v3; outIndices[i++] = v1; } flipStart = i; } length = 0; outIndices[i++] = v1; outIndices[i++] = v2; while (actcGetNextVert(tc, &v3) != ACTC_PRIM_COMPLETE) { if (i + 1 > memb) goto no_profit; outIndices[i++] = v3; ++length; } primCount++; } ACTC_CALL(actcEndOutput(tc)); puts(""); printf("%u alloc\n", memb); if (outMemb) *outMemb = i; memb = tmp; // for (i = *outMemb-12; i != *outMemb; ++i) // outIndices[i] = 0; #if 0 puts("- INDICES:"); for (i = 0; i != *outMemb; ++i) printf("%u%s", outIndices[i], (!((i+1) % 3)?"\n":", ")); puts(""); #endif if (!(newIndices = _glhckRealloc(outIndices, memb, i, sizeof(glhckImportIndexData)))) goto out_of_memory; outIndices = newIndices; printf("%u indices\n", memb); printf("%u out indicies\n", i); printf("%u tristrips\n", primCount); printf("%u profit\n", memb - i); actcDelete(tc); RET(0, "%p", outIndices); return outIndices; not_valid: DEBUG(GLHCK_DBG_ERROR, "Tristripper: not valid triangle indices"); goto fail; out_of_memory: DEBUG(GLHCK_DBG_ERROR, "Tristripper: out of memory"); goto fail; actc_fail: DEBUG(GLHCK_DBG_ERROR, "Tristripper: init failed"); goto fail; no_profit: DEBUG(GLHCK_DBG_CRAP, "Tripstripper: no profit from stripping, fallback to triangles"); fail: IFDO(actcDelete, tc); IFDO(_glhckFree, outIndices); RET(0, "%p", NULL); return NULL; #endif }
// draw a mesh consisting of vertices, facets, colors, normals etc. void DispCmdTriMesh::putdata(const float * vertices, const float * normals, const float * colors, int num_verts, const int * facets, int num_facets, int enablestrips, VMDDisplayList * dobj) { int builtstrips = 0; #if defined(VMDACTC) if (enablestrips) { // Rearrange face data into triangle strips ACTCData *tc = actcNew(); // intialize ACTC stripification library int fsize = num_facets * 3; int i, ind, ii; int iPrimCount = 0; int iCurrPrimSize; // XXX over-allocate the vertex and facet buffers to prevent an // apparent bug in ACTC 1.1 from crashing VMD. This was causing // Surf surfaces to crash ACTC at times. int *p_iPrimSize = new int[fsize + 6]; // num vertices in a primitive unsigned int *f2 = new uint[fsize + 6]; if (tc == NULL) { msgErr << "ACTC initialization failed, using triangle mesh." << sendmsg; } else { msgInfo << "Performing ACTC Triangle Consolidation..." << sendmsg; // only produce strips, not fans, give a ridiculously high min value. actcParami(tc, ACTC_OUT_MIN_FAN_VERTS, 2147483647); // disabling honoring vertex winding order might allow ACTC to // consolidate more triangles into strips, but this is only useful // if VMD has two-sided lighting enabled. // actcParami(tc, ACTC_OUT_HONOR_WINDING, ACTC_TRUE); // send triangle data over to ACTC library actcBeginInput(tc); for (ii=0; ii < num_facets; ii++) { ind = ii * 3; if ((actcAddTriangle(tc, facets[ind], facets[ind + 1], facets[ind + 2])) != ACTC_NO_ERROR) { msgInfo << "ACTC Add Triangle Error." << sendmsg; } } actcEndInput(tc); // get triangle strips back from ACTC, loop through once to get sizes actcBeginOutput(tc); i = 0; while ((actcStartNextPrim(tc, &f2[i], &f2[i+1]) != ACTC_DATABASE_EMPTY)) { iCurrPrimSize = 2; // if we're here, we got 2 vertices i+=2; // increment array position while (actcGetNextVert(tc, &f2[i]) != ACTC_PRIM_COMPLETE) { iCurrPrimSize++; // increment number of vertices for this primitive i++; // increment array position } p_iPrimSize[iPrimCount] = iCurrPrimSize; // save vertex count iPrimCount++; // increment primitive counter } actcEndOutput(tc); msgInfo << "ACTC: Created " << iPrimCount << " triangle strips" << sendmsg; msgInfo << "ACTC: Average vertices per strip = " << i / iPrimCount << sendmsg; // Draw triangle strips, uses double-sided lighting until we change // things to allow the callers to specify the desired lighting // explicitly. DispCmdTriStrips::putdata(vertices, normals, colors, num_verts, p_iPrimSize, iPrimCount, f2, i, 1, dobj); // delete temporary memory delete [] f2; delete [] p_iPrimSize; // delete ACTC handle actcDelete(tc); builtstrips = 1; // don't generate a regular triangle mesh } } #endif if (!builtstrips) { // make a triangle mesh (no strips) DispCmdTriMesh *ptr = (DispCmdTriMesh *) (dobj->append(DTRIMESH_C4F_N3F_V3F, sizeof(DispCmdTriMesh) + sizeof(float) * num_verts * 10 + sizeof(int) * num_facets * 3)); if (ptr == NULL) return; ptr->pervertexcolors=1; ptr->numverts=num_verts; ptr->numfacets=num_facets; float *cnv; int *f; ptr->getpointers(cnv, f); #if 1 int ind10, ind3; for (ind10=0,ind3=0; ind10<num_verts*10; ind10+=10,ind3+=3) { cnv[ind10 ] = colors[ind3 ]; cnv[ind10 + 1] = colors[ind3 + 1]; cnv[ind10 + 2] = colors[ind3 + 2]; cnv[ind10 + 3] = 1.0; cnv[ind10 + 4] = normals[ind3 ]; cnv[ind10 + 5] = normals[ind3 + 1]; cnv[ind10 + 6] = normals[ind3 + 2]; cnv[ind10 + 7] = vertices[ind3 ]; cnv[ind10 + 8] = vertices[ind3 + 1]; cnv[ind10 + 9] = vertices[ind3 + 2]; } #else int i, ind, ind2; for (i=0; i<num_verts; i++) { ind = i * 10; ind2 = i * 3; cnv[ind ] = colors[ind2 ]; cnv[ind + 1] = colors[ind2 + 1]; cnv[ind + 2] = colors[ind2 + 2]; cnv[ind + 3] = 1.0; cnv[ind + 4] = normals[ind2 ]; cnv[ind + 5] = normals[ind2 + 1]; cnv[ind + 6] = normals[ind2 + 2]; cnv[ind + 7] = vertices[ind2 ]; cnv[ind + 8] = vertices[ind2 + 1]; cnv[ind + 9] = vertices[ind2 + 2]; } #endif memcpy(f, facets, ptr->numfacets * 3 * sizeof(int)); } }
int main(int argc, char **argv) { ACTCData *tc; int i; uint v1, v2, v3, v4, v5, v6, v7; tc = actcNew(); if(tc == NULL) { printf("failed to allocate TC structure\n"); exit(1); } i = actcParami(tc, ACTC_OUT_MAX_PRIM_VERTS, 2); if(i != ACTC_INVALID_VALUE) { printf("didn't get error on MAX_PRIM_VERTS=2 as expected\n"); exit(1); } if(i != actcGetError(tc)) { printf("error returned didn't equal the error stored\n"); exit(1); } /* Triangle 1,2,3 */ CHECKERR(actcBeginInput(tc)); CHECKERR(actcAddTriangle(tc, 1, 2, 3)); CHECKERR(actcEndInput(tc)); CHECKERR(actcBeginOutput(tc)); CHECKNOT(actcStartNextPrim(tc, &v1, &v2), ACTC_PRIM_STRIP); CHECKERR(actcGetNextVert(tc, &v3)); CHECKNOT(actcGetNextVert(tc, &v4), ACTC_PRIM_COMPLETE); CHECKERR(actcEndOutput(tc)); if( ! (v1 == 1 && v2 == 2 && v3 == 3) && ! (v1 == 2 && v2 == 3 && v3 == 1) && ! (v1 == 3 && v2 == 1 && v3 == 2) ) { printf("unexpected vertex output: %u %u %u\n", v1, v2, v3); exit(1); } /* Quad 1,2,3,4 */ CHECKERR(actcBeginInput(tc)); CHECKERR(actcAddTriangle(tc, 1, 2, 4)); CHECKERR(actcAddTriangle(tc, 4, 2, 3)); CHECKERR(actcEndInput(tc)); CHECKERR(actcBeginOutput(tc)); CHECKNOT(actcStartNextPrim(tc, &v1, &v2), ACTC_PRIM_STRIP); CHECKERR(actcGetNextVert(tc, &v3)); CHECKERR(actcGetNextVert(tc, &v4)); CHECKNOT(actcGetNextVert(tc, &v5), ACTC_PRIM_COMPLETE); CHECKERR(actcEndOutput(tc)); /* * Next two tests could be fooled by returning same triangle twice, * which would certainly be possible, say, if vertices and edges were * erroneously not removed from their membership lists. See tctest2 * for a more exhaustive and accurate testing framework. */ if( ! (v1 == 1 && v2 == 2 && v3 == 4) && ! (v1 == 2 && v2 == 4 && v3 == 1) && ! (v1 == 4 && v2 == 1 && v3 == 2) && ! (v1 == 2 && v2 == 3 && v3 == 4) && ! (v1 == 3 && v2 == 4 && v3 == 2) && ! (v1 == 4 && v2 == 2 && v3 == 3) ) { printf("%d : unexpected vertex output: %u %u %u\n", __LINE__, v1, v2, v3); exit(1); } if( ! (v2 == 1 && v3 == 4 && v4 == 2) && ! (v2 == 2 && v3 == 1 && v4 == 4) && ! (v2 == 4 && v3 == 2 && v4 == 1) && ! (v2 == 2 && v3 == 4 && v4 == 3) && ! (v2 == 3 && v3 == 2 && v4 == 4) && ! (v2 == 4 && v3 == 3 && v4 == 2) ) { printf("%d : unexpected vertex output: %u %u %u\n", __LINE__, v2, v3, v4); exit(1); } /* independent triangles 1,2,3 and 4,5,6 */ CHECKERR(actcBeginInput(tc)); CHECKERR(actcAddTriangle(tc, 1, 2, 3)); CHECKERR(actcAddTriangle(tc, 4, 5, 6)); CHECKERR(actcEndInput(tc)); CHECKERR(actcBeginOutput(tc)); CHECKNOT(actcStartNextPrim(tc, &v1, &v2), ACTC_PRIM_STRIP); CHECKERR(actcGetNextVert(tc, &v3)); CHECKNOT(actcGetNextVert(tc, &v4), ACTC_PRIM_COMPLETE); CHECKNOT(actcStartNextPrim(tc, &v4, &v5), ACTC_PRIM_STRIP); CHECKERR(actcGetNextVert(tc, &v6)); CHECKNOT(actcGetNextVert(tc, &v7), ACTC_PRIM_COMPLETE); CHECKERR(actcEndOutput(tc)); /* * Next two tests could be fooled by returning same triangle twice, * which would certainly be possible, say, if vertices and edges were * erroneously not removed from their membership lists. See tctest2 * for a more exhaustive and accurate testing framework. */ if( ! (v1 == 1 && v2 == 2 && v3 == 3) && ! (v1 == 2 && v2 == 3 && v3 == 1) && ! (v1 == 3 && v2 == 1 && v3 == 2) && ! (v1 == 4 && v2 == 5 && v3 == 6) && ! (v1 == 5 && v2 == 6 && v3 == 4) && ! (v1 == 6 && v2 == 4 && v3 == 5) ) { printf("%d : unexpected vertex output: %u %u %u\n", __LINE__, v1, v2, v3); exit(1); } if( ! (v4 == 1 && v5 == 2 && v6 == 3) && ! (v4 == 2 && v5 == 3 && v6 == 1) && ! (v4 == 3 && v5 == 1 && v6 == 2) && ! (v4 == 4 && v5 == 5 && v6 == 6) && ! (v4 == 5 && v5 == 6 && v6 == 4) && ! (v4 == 6 && v5 == 4 && v6 == 5) ) { printf("%d : unexpected vertex output: %u %u %u\n", __LINE__, v1, v2, v3); exit(1); } /* Triangle 1,2,3, but delete it */ CHECKERR(actcBeginInput(tc)); CHECKERR(actcAddTriangle(tc, 1, 2, 3)); CHECKERR(actcEndInput(tc)); CHECKERR(actcBeginOutput(tc)); CHECKERR(actcMakeEmpty(tc)); CHECKNOT(i = actcStartNextPrim(tc, &v1, &v2), ACTC_IDLE); actcDelete(tc); exit(0); }