public ImColor(ImVec4 col) { Value = col; }
internal ImRect RenderText(float size, ImVec2 pos, uint col, ImVec4 clip_rect, char[] text, int text_begin, int text_end, ImDrawList draw_list, float wrap_width = 0.0f, bool cpu_fine_clip = false) { if (text_end == -1) { text_end = text.Length; // FIXME-OPT: Need to avoid this. } // Align to be pixel perfect pos.x = (int)pos.x + DisplayOffset.x; pos.y = (int)pos.y + DisplayOffset.y; float x = pos.x; float y = pos.y; if (y > clip_rect.w) { return(new ImRect()); } float scale = size / FontSize; float line_height = FontSize * scale; bool word_wrap_enabled = (wrap_width > 0.0f); int word_wrap_eol = -1; int vtx_write = draw_list._VtxWritePtr; int idx_write = draw_list._IdxWritePtr; uint vtx_current_idx = draw_list._VtxCurrentIdx; int s = text_begin; if (!word_wrap_enabled && y + line_height < clip_rect.y) { while (s < text_end && text[s] != '\n') // Fast-forward to next line { s++; } } while (s < text_end) { if (word_wrap_enabled) { // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. if (word_wrap_eol != -1) { word_wrap_eol = CalcWordWrapPositionA(scale, text, s, text_end, wrap_width - (x - pos.x)); if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. { word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below } } if (s >= word_wrap_eol) { x = pos.x; y += line_height; word_wrap_eol = -1; // Wrapping skips upcoming blanks while (s < text_end) { char wc = text[s]; if (char.IsSeparator(wc)) { s++; } else if (wc == '\n') { s++; break; } else { break; } } continue; } } // Decode and advance source char c = text[s++]; //if (c< 0x80) //{ // s += 1; //} //else //{ // s += ImTextCharFromUtf8(&c, s, text_end); // if (c == 0) // break; //} if (c < 32) { if (c == '\n') { x = pos.x; y += line_height; if (y > clip_rect.w) { break; } if (!word_wrap_enabled && y + line_height < clip_rect.y) { while (s < text_end && text[s] != '\n') // Fast-forward to next line { s++; } } continue; } if (c == '\r') { continue; } } float char_width = 0.0f; Glyph glyph; if (FindGlyph(c, out glyph)) { char_width = glyph.XAdvance * scale; // Arbitrarily assume that both space and tabs are empty glyphs as an optimization if (c != ' ' && c != '\t') { // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w float y1 = (float)(y + glyph.Y0 * scale); float y2 = (float)(y + glyph.Y1 * scale); float x1 = (float)(x + glyph.X0 * scale); float x2 = (float)(x + glyph.X1 * scale); if (x1 <= clip_rect.z && x2 >= clip_rect.x) { // Render a character float u1 = glyph.U0; float v1 = glyph.V0; float u2 = glyph.U1; float v2 = glyph.V1; // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads. if (cpu_fine_clip) { if (x1 < clip_rect.x) { u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1); x1 = clip_rect.x; } if (y1 < clip_rect.y) { v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1); y1 = clip_rect.y; } if (x2 > clip_rect.z) { u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1); x2 = clip_rect.z; } if (y2 > clip_rect.w) { v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1); y2 = clip_rect.w; } if (y1 >= y2) { x += char_width; continue; } } // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug build. // Inlined here: { draw_list.IdxBuffer[idx_write++] = (ImDrawIdx)(vtx_current_idx); draw_list.IdxBuffer[idx_write++] = (ImDrawIdx)(vtx_current_idx + 1); draw_list.IdxBuffer[idx_write++] = (ImDrawIdx)(vtx_current_idx + 2); draw_list.IdxBuffer[idx_write++] = (ImDrawIdx)(vtx_current_idx); draw_list.IdxBuffer[idx_write++] = (ImDrawIdx)(vtx_current_idx + 2); draw_list.IdxBuffer[idx_write++] = (ImDrawIdx)(vtx_current_idx + 3); draw_list.VtxBuffer[vtx_write++] = new ImDrawVert() { pos = new ImVec2(x1, y1), uv = new ImVec2(u1, v1), col = col }; draw_list.VtxBuffer[vtx_write++] = new ImDrawVert() { pos = new ImVec2(x2, y1), uv = new ImVec2(u2, v1), col = col }; draw_list.VtxBuffer[vtx_write++] = new ImDrawVert() { pos = new ImVec2(x2, y2), uv = new ImVec2(u2, v2), col = col }; draw_list.VtxBuffer[vtx_write++] = new ImDrawVert() { pos = new ImVec2(x1, y2), uv = new ImVec2(u1, v2), col = col }; vtx_current_idx += 4; } } } } x += char_width; } draw_list._VtxWritePtr = vtx_write; draw_list._VtxCurrentIdx = vtx_current_idx; draw_list._IdxWritePtr = idx_write; return(new ImRect(pos, new ImVec2(x, y + line_height))); }