void BufferStoreIsoscelesTriangle(GG::GL2DVertexBuffer& buffer, const GG::Pt& ul, const GG::Pt& lr, ShapeOrientation orientation) { double x1_, y1_, x2_, y2_, x3_, y3_; FindIsoscelesTriangleVertices(ul, lr, orientation, x1_, y1_, x2_, y2_, x3_, y3_); buffer.store(x1_, y1_); buffer.store(x2_, y2_); buffer.store(x3_, y3_); }
/// Fills \a buffer with the ends points for the lines that connect /// technologies in \a techs void FillArcBuffer(GG::GL2DVertexBuffer& buffer, const std::set<std::string>& techs) { for (std::set<std::string>::const_iterator it = techs.begin(); it != techs.end(); ++it) { const std::vector<TechTreeLayout::Edge*> edges = m_layout.GetOutEdges(*it); //prerequisite edge for (std::vector<TechTreeLayout::Edge*>::const_iterator edge = edges.begin(); edge != edges.end(); edge++) { std::vector<std::pair<double, double> > points; const std::string& from = (*edge)->GetTechFrom(); const std::string& to = (*edge)->GetTechTo(); // Do not show lines leading to techs // we are not showing if (techs.find(to) == techs.end()) { continue; } // Remember what edges we are showing so // we can eventually highlight them m_edges_to_show[from].insert(to); if (!GetTech(from) || !GetTech(to)) { ErrorLogger() << "TechTreeArcs::FillArcBuffer missing arc endpoint tech " << from << "->" << to; continue; } (*edge)->ReadPoints(points); // To be able to draw all the lines in one call, // we will draw the with GL_LINES, which means all // vertices except the first and the last must occur twice for (unsigned i = 0; i < points.size() - 1; ++i){ buffer.store(points[i].first, points[i].second); buffer.store(points[i+1].first, points[i+1].second); } } } buffer.createServerBuffer(); }
void BufferStoreAngledCornerRectangleVertices(GG::GL2DVertexBuffer& buffer, const GG::Pt& ul, const GG::Pt& lr, int angle_offset, bool upper_left_angled, bool lower_right_angled, bool connect_bottom_line) { // these are listed in CCW order if (connect_bottom_line) buffer.store(Value(ul.x), Value(lr.y)); if (lower_right_angled) { buffer.store(Value(lr.x) - angle_offset - 3,Value(lr.y)); // don't know why, but - 3 here and the next line seem to make things symmetric top-left and bottom-right buffer.store(Value(lr.x), Value(lr.y) - angle_offset - 3); } else { buffer.store(Value(lr.x), Value(lr.y)); } buffer.store(Value(lr.x), Value(ul.y)); if (upper_left_angled) { buffer.store(Value(ul.x) + angle_offset, Value(ul.y)); buffer.store(Value(ul.x), Value(ul.y) + angle_offset); } else { buffer.store(Value(ul.x), Value(ul.y)); } buffer.store(Value(ul.x), Value(lr.y)); }
void BufferStorePartlyRoundedRectVertices(GG::GL2DVertexBuffer& buffer, const GG::Pt& ul, const GG::Pt& lr, int radius, bool ur_round, bool ul_round, bool ll_round, bool lr_round) { const double PI = 3.141594; buffer.store(lr.x, ul.y + radius); if (ur_round) BufferStoreCircleArcVertices(buffer, GG::Pt(lr.x - 2 * radius, ul.y), GG::Pt(lr.x, ul.y + 2 * radius), 0.0, PI / 2.0, false); else buffer.store(lr.x, ul.y); if (ul_round) BufferStoreCircleArcVertices(buffer, ul, GG::Pt(ul.x + 2 * radius, ul.y + 2 * radius), PI / 2.0, PI, false); else buffer.store(ul.x, ul.y); if (ll_round) BufferStoreCircleArcVertices(buffer, GG::Pt(ul.x, lr.y - 2 * radius), GG::Pt(ul.x + 2 * radius, lr.y), PI, 3.0 * PI / 2.0, false); else buffer.store(ul.x, lr.y); if (lr_round) BufferStoreCircleArcVertices(buffer, GG::Pt(lr.x - 2 * radius, lr.y - 2 * radius), lr, 3.0 * PI / 2.0, 0.0, false); else buffer.store(lr.x, lr.y); buffer.store(lr.x, ul.y + radius); }
void DrawArrow(GG::Pt begin, GG::Pt end) { double head_width = 5.0; // A vector (math) of the arrow we wish to draw GG::Pt direction = end - begin; double length = sqrt(1.0*(Value(direction.x)*Value(direction.x) + Value(direction.y)*Value(direction.y))); if (length == 0) { return; } // The point in the main line of the arrow, // paraller to which the head ends // \. // \. // --------h--> // /. // /. // h is at the handle GG::Pt handle; // How much to move off the handle to get to // the end point of one of the head lines GG::X delta_x; GG::Y delta_y; if (direction.x != 0 && direction.y != 0) { // In a skewed arrow we need // a bit of geometry to figure out the head double x = Value(direction.x); double y = Value(direction.y); double normalizer = head_width / sqrt(1 + x*x / (y*y)); delta_x = GG::X(normalizer); delta_y = GG::Y(- x / y * normalizer); handle = end - GG::Pt((head_width / length) * direction.x, (head_width / length) * direction.y); } else if (direction.x == 0) { // Vertical arrow handle = end; handle.y -= boost::math::sign(Value(direction.y))*GG::Y(head_width); delta_x = GG::X(head_width); delta_y = GG::Y0; } else { //horizontal arrow handle = end; handle.x -= boost::math::sign(Value(direction.x)) * GG::X(head_width); delta_x = GG::X0; delta_y = GG::Y(head_width); } GG::Pt left_head = handle; GG::Pt right_head = handle; left_head.x += delta_x; left_head.y += delta_y; // The other line is on the opposite side of the handle right_head.x -= delta_x; right_head.y -= delta_y; GG::glColor(GG::CLR_WHITE); glLineWidth(2); glDisable(GL_TEXTURE_2D); GG::GL2DVertexBuffer verts; verts.reserve(6); verts.store(Value(begin.x), Value(begin.y)); verts.store(Value(end.x), Value(end.y)); verts.store(Value(end.x), Value(end.y)); verts.store(Value(left_head.x), Value(left_head.y)); verts.store(Value(end.x), Value(end.y)); verts.store(Value(right_head.x),Value(right_head.y)); verts.activate(); glDrawArrays(GL_LINES, 0, verts.size()); glEnable(GL_TEXTURE_2D); }
void BufferStoreCircleArcVertices(GG::GL2DVertexBuffer& buffer, const GG::Pt& ul, const GG::Pt& lr, double theta1, double theta2, bool filled_shape, int num_slices, bool fan) { int wd = Value(lr.x - ul.x), ht = Value(lr.y - ul.y); double center_x = Value(ul.x + wd / 2.0); double center_y = Value(ul.y + ht / 2.0); double r = std::min(wd / 2.0, ht / 2.0); const double PI = 3.141594; // correct theta* values to range [0, 2pi) if (theta1 < 0) theta1 += (int(-theta1 / (2 * PI)) + 1) * 2 * PI; else if (theta1 >= 2 * PI) theta1 -= int(theta1 / (2 * PI)) * 2 * PI; if (theta2 < 0) theta2 += (int(-theta2 / (2 * PI)) + 1) * 2 * PI; else if (theta2 >= 2 * PI) theta2 -= int(theta2 / (2 * PI)) * 2 * PI; int SLICES = 50; if (num_slices <= 0) SLICES = std::min(std::max(12, 3 + std::max(wd, ht)), 50); // this is a good guess at how much to tesselate the circle coordinates (50 segments max) else SLICES = num_slices; const double HORZ_THETA = (2 * PI) / SLICES; static std::map<int, std::vector<double>> unit_circle_coords; std::vector<double>& unit_vertices = unit_circle_coords[SLICES]; bool calc_vertices = unit_vertices.size() == 0; if (calc_vertices) { unit_vertices.resize(2 * (SLICES + 1), 0.0); double theta = 0.0f; for (int j = 0; j <= SLICES; theta += HORZ_THETA, ++j) { // calculate x,y values for each point on a unit circle divided into SLICES arcs unit_vertices[j*2] = std::cos(-theta); unit_vertices[j*2+1] = std::sin(-theta); } } int first_slice_idx = int(theta1 / HORZ_THETA + 1); int last_slice_idx = int(theta2 / HORZ_THETA - 1); if (theta1 >= theta2) last_slice_idx += SLICES; if (fan) { // store a triangle fan vertex list, specifying each vertex just once if (filled_shape) // specify the central vertex first, to act as the pivot vertex for the fan buffer.store(static_cast<GLfloat>(center_x), static_cast<GLfloat>(center_y)); // if not filled_shape, assumes a previously-specified vertex in the buffer will act as the pivot for the fan // point on circle at angle theta1 double theta1_x = std::cos(-theta1), theta1_y = std::sin(-theta1); buffer.store(static_cast<GLfloat>(center_x + theta1_x * r), static_cast<GLfloat>(center_y + theta1_y * r)); // angles in between theta1 and theta2, if any for (int i = first_slice_idx; i <= last_slice_idx + 1; ++i) { int X = (i > SLICES ? (i - SLICES) : i) * 2, Y = X + 1; buffer.store(static_cast<GLfloat>(center_x + unit_vertices[X] * r), static_cast<GLfloat>(center_y + unit_vertices[Y] * r)); } // theta2 double theta2_x = std::cos(-theta2), theta2_y = std::sin(-theta2); buffer.store(static_cast<GLfloat>(center_x + theta2_x * r), static_cast<GLfloat>(center_y + theta2_y * r)); } else { // (not a fan) store a list of complete lines / triangles // if storing a filled_shape, the first point in each triangle should be the centre of the arc std::pair<GLfloat, GLfloat> first_point = {static_cast<GLfloat>(center_x), static_cast<GLfloat>(center_y)}; // (not used for non-filled-shape) // angles in between theta1 and theta2, if any for (int i = first_slice_idx - 1; i <= last_slice_idx; ++i) { if (filled_shape) { buffer.store(first_point.first, first_point.second); // list of triangles: need two more vertices on the arc per starting vertex } // else: list of lines, with two vertices each int X = (i > SLICES ? (i - SLICES) : i) * 2; int Y = X + 1; buffer.store(static_cast<GLfloat>(center_x + unit_vertices[X] * r), static_cast<GLfloat>(center_y + unit_vertices[Y] * r)); int next_i = i + 1; X = (next_i > SLICES ? (next_i - SLICES) : next_i) * 2; Y = X + 1; buffer.store(static_cast<GLfloat>(center_x + unit_vertices[X] * r), static_cast<GLfloat>(center_y + unit_vertices[Y] * r)); } // theta2 if (filled_shape) { buffer.store(first_point.first, first_point.second); } int i = last_slice_idx + 1; int X = (i > SLICES ? (i - SLICES) : i) * 2; int Y = X + 1; buffer.store(static_cast<GLfloat>(center_x + unit_vertices[X] * r), static_cast<GLfloat>(center_y + unit_vertices[Y] * r)); double theta2_x = std::cos(-theta2), theta2_y = std::sin(-theta2); buffer.store(static_cast<GLfloat>(center_x + theta2_x * r), static_cast<GLfloat>(center_y + theta2_y * r)); } }
void BufferStoreRectangle(GG::GL2DVertexBuffer& buffer, const GG::Rect& area, const GG::Rect& border_thickness) { GG::X inner_x1(area.ul.x + border_thickness.ul.x); GG::Y inner_y1(area.ul.y + border_thickness.ul.y); GG::X inner_x2(area.lr.x - border_thickness.lr.x); GG::Y inner_y2(area.lr.y - border_thickness.lr.y); buffer.reserve(14); buffer.store(inner_x2, inner_y1); buffer.store(area.lr.x, area.ul.y); buffer.store(inner_x1, inner_y1); buffer.store(area.ul.x, area.ul.y); buffer.store(inner_x1, inner_y2); buffer.store(area.ul.x, area.lr.y); buffer.store(inner_x2, inner_y2); buffer.store(area.lr.x, area.lr.y); buffer.store(inner_x2, inner_y1); buffer.store(area.lr.x, area.ul.y); buffer.store(inner_x2, inner_y1); buffer.store(inner_x1, inner_y1); buffer.store(inner_x1, inner_y2); buffer.store(inner_x2, inner_y2); }