/*!******************************************************************************************** @Function generate_border @Input anchor_index The anchor index to center the quad around. @Input left_offset The width of the quad left from the anchor. @Input right_offset The width of the quad right from the anchor. @Input pivot The pivot used for all vertices. @Input texmat The texture atlas used for uv-coordinate calculation. @Output pivotquads The generated pivotquad vertex data. @Output triangle Triangle indices used for rendering of the pivotquads. @Description Generates a single quad which can be used e.g. to render a rectangle behind text. ***********************************************************************************************/ void generate_border(const int anchor_index, const int left_offset, const int right_offset, const PVRTVec2 &pivot, PVRTMat3 &texmat, PVRTPivotQuadVertexVector &pivotquads, PVRTTriangleVector &triangles) { unsigned int triangle_index = pivotquads.size(); PVRTVec3 uvcoords; PVRTPivotQuadVertex vertex; vertex.origin = pivot; // Left cap uvcoords = texmat * PVRTVec3(0.0f, 0.0f, 1.0f); vertex.word_index = -anchor_index - left_offset; vertex.height_index = 0; vertex.u = (PVRTuint8)(uvcoords.x * 255.0f); vertex.v = (PVRTuint8)(uvcoords.y * 255.0f); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(0.5f, 0.0f, 1.0f); vertex.word_index = -anchor_index - left_offset + 1; vertex.height_index = 0; vertex.u = (PVRTuint8)(uvcoords.x * 255.0f); vertex.v = (PVRTuint8)(uvcoords.y * 255.0f); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(0.0f, 1.0f, 1.0f); vertex.word_index = -anchor_index - left_offset; vertex.height_index = 1; vertex.u = (PVRTuint8)(uvcoords.x * 255.0f); vertex.v = (PVRTuint8)(uvcoords.y * 255.0f); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(0.5f, 1.0f, 1.0f); vertex.word_index = -anchor_index - left_offset + 1; vertex.height_index = 1; vertex.u = (PVRTuint8)(uvcoords.x * 255.0f); vertex.v = (PVRTuint8)(uvcoords.y * 255.0f); pivotquads.push_back(vertex); PVRTTriangle t0 = { triangle_index, triangle_index + 1, triangle_index + 3 }; PVRTTriangle t1 = { triangle_index, triangle_index + 3, triangle_index + 2 }; triangles.push_back(t0); triangles.push_back(t1); triangle_index = pivotquads.size(); // Middle part uvcoords = texmat * PVRTVec3(0.5f, 0.0f, 1.0f); vertex.word_index = -anchor_index - left_offset + 1; vertex.height_index = 0; vertex.u = (PVRTuint8)(uvcoords.x * 255.0f); vertex.v = (PVRTuint8)(uvcoords.y * 255.0f); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(0.5f, 0.0f, 1.0f); vertex.word_index = anchor_index + right_offset - 1; vertex.height_index = 0; vertex.u = (PVRTuint8)(uvcoords.x * 255.0f); vertex.v = (PVRTuint8)(uvcoords.y * 255.0f); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(0.5f, 1.0f, 1.0f); vertex.word_index = -anchor_index - left_offset + 1; vertex.height_index = 1; vertex.u = (PVRTuint8)(uvcoords.x * 255.0f); vertex.v = (PVRTuint8)(uvcoords.y * 255.0f); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(0.5f, 1.0f, 1.0f); vertex.word_index = anchor_index + right_offset - 1; vertex.height_index = 1; vertex.u = (PVRTuint8)(uvcoords.x * 255.0f); vertex.v = (PVRTuint8)(uvcoords.y * 255.0f); pivotquads.push_back(vertex); PVRTTriangle t2 = { triangle_index, triangle_index + 1, triangle_index + 3 }; PVRTTriangle t3 = { triangle_index, triangle_index + 3, triangle_index + 2 }; triangles.push_back(t2); triangles.push_back(t3); triangle_index = pivotquads.size(); // Right cap uvcoords = texmat * PVRTVec3(0.5f, 0.0f, 1.0f); vertex.word_index = anchor_index + right_offset - 1; vertex.height_index = 0; vertex.u = (PVRTuint8)(uvcoords.x * 255.0f); vertex.v = (PVRTuint8)(uvcoords.y * 255.0f); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(1.0f, 0.0f, 1.0f); vertex.word_index = anchor_index + right_offset; vertex.height_index = 0; vertex.u = (PVRTuint8)(uvcoords.x * 255.0f); vertex.v = (PVRTuint8)(uvcoords.y * 255.0f); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(0.5f, 1.0f, 1.0f); vertex.word_index = anchor_index + right_offset - 1; vertex.height_index = 1; vertex.u = (PVRTuint8)(uvcoords.x * 255.0f); vertex.v = (PVRTuint8)(uvcoords.y * 255.0f); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(1.0f, 1.0f, 1.0f); vertex.word_index = anchor_index + right_offset; vertex.height_index = 1; vertex.u = (PVRTuint8)(uvcoords.x * 255.0f); vertex.v = (PVRTuint8)(uvcoords.y * 255.0f); pivotquads.push_back(vertex); PVRTTriangle t4 = { triangle_index, triangle_index + 1, triangle_index + 3 }; PVRTTriangle t5 = { triangle_index, triangle_index + 3, triangle_index + 2 }; triangles.push_back(t4); triangles.push_back(t5); }
/*!******************************************************************************************** @Function convert_signs @Input layer The map layer to extract the texts from. @Input atlas The texture atlas used for uv-coordinate calculation. @Output pivotquads The generated pivotquad vertex data. @Output triangles Triangle indices used for rendering of the pivotquads. @Description Generates pivotquads for the signs which will be screen-space aligned when being rendered. ***********************************************************************************************/ void convert_signs(const PVRTMapLayer &layer, const PVRTTextureAtlas &atlas, PVRTPivotQuadVertexVector &pivotquads, PVRTTriangleVector &triangles) { unsigned int numTotalSigns = layer.indexset.signs.size(); // Pre-allocate to prevent reallocations pivotquads.reserve(pivotquads.size() + numTotalSigns * 4); triangles.reserve(triangles.size() + numTotalSigns * 2); for (unsigned int j=0; j < numTotalSigns; j++) { const unsigned int index = pivotquads.size(); string name(layer.indexset.signs[j].szName); PVRTVec2 pos = layer.indexset.signs[j].position; if (!atlas.Contains(name)) { cerr << "Error: Texture atlas does not contain " << name << endl; continue; } PVRTMat3 texmat = atlas.GetTextureMatrix(name); PVRTVec3 uvcoords; PVRTPivotQuadVertex vertex; vertex.origin = pos; uvcoords = texmat * PVRTVec3(0.0f, 0.0f, 255.0f); vertex.word_index = 0; vertex.height_index = 0; vertex.u = (PVRTuint8)(uvcoords.x); vertex.v = (PVRTuint8)(uvcoords.y); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(255.0f, 0.0f, 255.0f); vertex.word_index = 1; vertex.height_index = 0; vertex.u = (PVRTuint8)(uvcoords.x); vertex.v = (PVRTuint8)(uvcoords.y); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(0.0f, 255.0f, 255.0f); vertex.word_index = 0; vertex.height_index = 1; vertex.u = (PVRTuint8)(uvcoords.x); vertex.v = (PVRTuint8)(uvcoords.y); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(255.0f, 255.0f, 255.0f); vertex.word_index = 1; vertex.height_index = 1; vertex.u = (PVRTuint8)(uvcoords.x); vertex.v = (PVRTuint8)(uvcoords.y); pivotquads.push_back(vertex); PVRTTriangle t0 = { index, index + 1, index + 3 }; PVRTTriangle t1 = { index, index + 3, index + 2 }; triangles.push_back(t0); triangles.push_back(t1); } }
/*!******************************************************************************************** @Function TriangulatePolygon @Input coordinates Coordinate array for the polygon. @Input polygon The polygon definition. @Output triangle_coords The resulting coordinates of the triangulation. @Output triangle_indices The resulting triangle indices of the polygon. @Return True if the polygon could be triangulated, false otherwise. @Description Triangulates a non-self-intersecting polygon. ***********************************************************************************************/ bool TriangulatePolygon(const PVRTCoordinateVector &coordinates, const PVRTPolygon &polygon, PVRTCoordinateVector &triangle_coords, PVRTTriangleVector &triangle_indices) { // Copy the vertices, the index structure will be built on top of that set // without modification of the vertices triangle_coords = coordinates; // allocate and initialize list of Vertices in polygon int num_vertices = (int)polygon.indices.size(); if (num_vertices < 3) return false; // Create a temporary storage area for the indices index_t *V = new index_t[num_vertices]; // The polygon should be defined in counter-clockwise order if (CalculatePolygonArea(coordinates, polygon) > 0.0f) { for (int v=0; v < num_vertices; v++) V[v] = polygon.indices[v]; } // if not, reverse the index array else { for(int v=0; v < num_vertices; v++) V[v] = polygon.indices[(num_vertices-1) - v]; } // This counter should prevent endless loops (which only should happen in degenerate polygon cases) int loop_counter = num_vertices * 2; // Remove nv-2 vertices, creating a triangle every iteration for (int v=num_vertices-1; num_vertices > 2; loop_counter--) { // We looped, there is an error in this polygon if (loop_counter <= 0) return false; // Get the indices for three consecutive vertices in the polygon forming a triangle int u = v % num_vertices; v = (u + 1) % num_vertices; int w = (v + 1) % num_vertices; // Check if there is no point which lies within this triangle if (IsPolygonEar(coordinates, u, v, w, num_vertices, V)) { // No point found, that means it's an ear PVRTTriangle t = { V[u], V[v], V[w] }; triangle_indices.push_back(t); // Remove the triangle from the polygon by removing v for (int s=v; s < num_vertices-1; s++) V[s] = V[s+1]; num_vertices--; // Re-initialize the loop counter loop_counter = num_vertices * 2; } } delete [] V; return true; }
/*!******************************************************************************************** @Function convert_texts @Input layer The map layer to extract the texts from. @Input atlas The texture atlas used for uv-coordinate calculation. @Output pivotquads The generated pivotquad vertex data. @Output triangles Triangle indices used for rendering of the pivotquads. @Description Generates pivotquads for the text strings which will be screen-space aligned when being rendered. ***********************************************************************************************/ void convert_texts(const PVRTMapLayer &layer, const PVRTTextureAtlas &atlas, PVRTPivotQuadVertexVector &pivotquads, PVRTTriangleVector &triangles) { unsigned int numTotalLetters = 0; for (unsigned int j=0; j < layer.indexset.texts.size(); j++) { numTotalLetters += strlen(layer.indexset.texts[j].szName); } // Pre-allocate to prevent reallocations pivotquads.reserve(pivotquads.size() + numTotalLetters * 4); triangles.reserve(triangles.size() + numTotalLetters * 2); for (unsigned int j=0; j < layer.indexset.texts.size(); j++) { const PVRTLinestrip &linestrip = layer.indexset.linestrips[layer.indexset.texts[j].index]; string name(layer.indexset.texts[j].szName); unsigned int numLetters = name.length(); float rand_pos = rand() / (float)RAND_MAX; // transform it to the range [0.2, 0.8] so that the streetnames are more in the middle of the street rand_pos = 0.2f + rand_pos * 0.6f; PVRTVec3 pos_3d = InterpolateLinestrip(layer.coordinates, linestrip, rand_pos); PVRTVec2 pos = PVRTVec2(pos_3d.x, pos_3d.y); int adjustedIndex = 0; unsigned int triangle_index = pivotquads.size(); // Calculate the total width unsigned int word_width = 0; for (unsigned int i=0; i < numLetters; i++) word_width += get_letter_spacing(name.at(i)); const int anchor_index = word_width / 2; size_t ordinal_pos; bool has_ordinal = contains_ordinal(name, ordinal_pos); for (unsigned int i=0; i < numLetters; i++) { if (name.at(i) == ' ') { adjustedIndex += get_letter_spacing(name.at(i)); continue; } triangle_index = pivotquads.size(); const int startIndex = adjustedIndex; int starty, endy; // If it contains an ordinal and the current letter is one if (has_ordinal && ((i == ordinal_pos) || i == (ordinal_pos + 1))) { adjustedIndex += 2; starty = 2; endy = 5; } else { adjustedIndex += get_letter_spacing(name.at(i)); get_height_indices(name.at(i), starty, endy); } string letter = name.substr(i, 1); PVRTMat3 texmat = atlas.GetTextureMatrix(letter); PVRTPivotQuadVertex vertex; vertex.origin = pos; PVRTVec3 uvcoords = texmat * PVRTVec3(0.0f, 0.0f, 255.0f); vertex.word_index = startIndex - anchor_index; vertex.height_index = starty; vertex.u = (PVRTuint8)(uvcoords.x); vertex.v = (PVRTuint8)(uvcoords.y); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(255.0f, 0.0f, 255.0f); vertex.word_index = adjustedIndex - anchor_index; vertex.height_index = starty; vertex.u = (PVRTuint8)(uvcoords.x); vertex.v = (PVRTuint8)(uvcoords.y); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(0.0f, 255.0f, 255.0f); vertex.word_index = startIndex - anchor_index; vertex.height_index = endy; vertex.u = (PVRTuint8)(uvcoords.x); vertex.v = (PVRTuint8)(uvcoords.y); pivotquads.push_back(vertex); uvcoords = texmat * PVRTVec3(255.0f, 255.0f, 255.0f); vertex.word_index = adjustedIndex - anchor_index; vertex.height_index = endy; vertex.u = (PVRTuint8)(uvcoords.x); vertex.v = (PVRTuint8)(uvcoords.y); pivotquads.push_back(vertex); PVRTTriangle t0 = { triangle_index, triangle_index + 1, triangle_index + 3 }; PVRTTriangle t1 = { triangle_index, triangle_index + 3, triangle_index + 2 }; triangles.push_back(t0); triangles.push_back(t1); } } }
bool TriangulatePolygon(const PVRTCoordinateVector &coordinates, const PVRTPolygon &polygon, PVRTCoordinateVector &triangle_coords, PVRTTriangleVector &triangles) { unsigned int numPoints = polygon.indices.size(); InitialiseTriangulationModule(numPoints, 2*numPoints, NULL); int paths = 1; int pathlens[1] = { polygon.indices.size() }; float maxDimension = -FLT_MAX; float *pCoordinates = new float[polygon.indices.size()*2]; for (unsigned int i=0; i < polygon.indices.size(); i++) { PVRTVec3 coord = coordinates[polygon.indices[i]].position; pCoordinates[i*2] = coord.x; pCoordinates[i*2+1] = coord.y; maxDimension = PVRT_MAX(coord.x, maxDimension); maxDimension = PVRT_MAX(coord.y, maxDimension); } ExternalTrapStruct TrapezoidsResult; TRI_ERROR_TYPES status = BuildPolygonTrapeziation(NULL, //do all subpaths at once maxDimension, // path data paths, pathlens, pCoordinates, // Specify a seed for the random number generator // This isn't critcal if the processing is offline so just use 0 0, // the resulting trap structure &TrapezoidsResult); delete [] pCoordinates; if (!AnalyzeTriangulationError(status)) { FreeTriangulationModuleMemory(); return false; } int MaxFFRecursionDepth = 10000; int FillModeIsOddEven = 0; int numVertices = 0; float *pVertices = NULL; int numTriangles = 0; TriIndicesType *pTriangleIndices = NULL; numTriangles = OutputIndexedTriangles(&TrapezoidsResult, MaxFFRecursionDepth, FillModeIsOddEven, true, &numVertices, &pVertices, &pTriangleIndices); for (int i=0; i < numTriangles; i++) { TriIndicesType triangle = pTriangleIndices[i]; PVRTVertex a = { PVRTVec3(pVertices[triangle.Ind[0]*2], pVertices[triangle.Ind[0]*2+1], 0.0f), PVRTVec2(0.0f, 0.0f) }; PVRTVertex b = { PVRTVec3(pVertices[triangle.Ind[1]*2], pVertices[triangle.Ind[1]*2+1], 0.0f), PVRTVec2(0.0f, 0.0f) }; PVRTVertex c = { PVRTVec3(pVertices[triangle.Ind[2]*2], pVertices[triangle.Ind[2]*2+1], 0.0f), PVRTVec2(0.0f, 0.0f) }; const unsigned int index_start = triangle_coords.size(); triangle_coords.push_back(a); triangle_coords.push_back(b); triangle_coords.push_back(c); PVRTTriangle tri = { index_start, index_start+1, index_start+2 }; triangles.push_back(tri); } FreeTriangulationModuleMemory(); return true; }