diff --git a/Minecraft.Client/Font.cpp b/Minecraft.Client/Font.cpp index db2a18c0..1040eaa0 100644 --- a/Minecraft.Client/Font.cpp +++ b/Minecraft.Client/Font.cpp @@ -45,46 +45,46 @@ Font::Font(Options *options, const wstring& name, Textures* textures, bool enfor random = new Random(); // Load the image - BufferedImage *img = textures->readImage(textureLocation->getTexture(), name); + BufferedImage *img = textures->readImage(textureLocation->getTexture(), name); /* - 4J - TODO try { - img = ImageIO.read(Textures.class.getResourceAsStream(name)); - } catch (IOException e) { - throw new RuntimeException(e); - } + img = ImageIO.read(Textures.class.getResourceAsStream(name)); + } catch (IOException e) { + throw new RuntimeException(e); + } */ - int w = img->getWidth(); - int h = img->getHeight(); - intArray rawPixels(w * h); - img->getRGB(0, 0, w, h, rawPixels, 0, w); + int w = img->getWidth(); + int h = img->getHeight(); + intArray rawPixels(w * h); + img->getRGB(0, 0, w, h, rawPixels, 0, w); - for (int i = 0; i < charC; i++) + for (int i = 0; i < charC; i++) { - int xt = i % m_cols; - int yt = i / m_cols; + int xt = i % m_cols; + int yt = i / m_cols; - int x = 7; - for (; x >= 0; x--) + int x = 7; + for (; x >= 0; x--) { - int xPixel = xt * 8 + x; - bool emptyColumn = true; - for (int y = 0; y < 8 && emptyColumn; y++) + int xPixel = xt * 8 + x; + bool emptyColumn = true; + for (int y = 0; y < 8 && emptyColumn; y++) { - int yPixel = (yt * 8 + y) * w; + int yPixel = (yt * 8 + y) * w; bool emptyPixel = (rawPixels[xPixel + yPixel] >> 24) == 0; // Check the alpha value - if (!emptyPixel) emptyColumn = false; - } - if (!emptyColumn) + if (!emptyPixel) emptyColumn = false; + } + if (!emptyColumn) { - break; - } - } + break; + } + } - if (i == ' ') x = 4 - 2; - charWidths[i] = x + 2; - } + if (i == ' ') x = 4 - 2; + charWidths[i] = x + 2; + } delete img; @@ -130,6 +130,7 @@ Font::~Font() } #endif +// Legacy helper used by renderCharacter() only. void Font::renderStyleLine(float x0, float y0, float x1, float y1) { Tesselator* t = Tesselator::getInstance(); @@ -146,7 +147,20 @@ void Font::renderStyleLine(float x0, float y0, float x1, float y1) t->end(); } -void Font::addCharacterQuad(wchar_t c) +void Font::addSolidQuad(float x0, float y0, float x1, float y1) +{ + Tesselator *t = Tesselator::getInstance(); + t->tex(0.0f, 0.0f); + t->vertex(x0, y1, 0.0f); + t->tex(0.0f, 0.0f); + t->vertex(x1, y1, 0.0f); + t->tex(0.0f, 0.0f); + t->vertex(x1, y0, 0.0f); + t->tex(0.0f, 0.0f); + t->vertex(x0, y0, 0.0f); +} + +void Font::emitCharacterGeometry(wchar_t c) { float xOff = c % m_cols * m_charWidth; float yOff = c / m_cols * m_charHeight; // was m_charWidth — wrong when glyphs aren't square @@ -180,52 +194,45 @@ void Font::addCharacterQuad(wchar_t c) t->tex(xOff / fontWidth, yOff / fontHeight); t->vertex(x0 + dx, y0, 0.0f); } - - xPos += static_cast(charWidths[c]); } +void Font::addCharacterQuad(wchar_t c) +{ + float height = m_charHeight - .01f; + float x0 = xPos; + float y0 = yPos; + float y1 = yPos + height; + float advance = static_cast(charWidths[c]); + + emitCharacterGeometry(c); + + if (m_underline) + { + addSolidQuad(x0, y1 - 1.0f, xPos + advance, y1); + } + + if (m_strikethrough) + { + float mid = y0 + height * 0.5f; + addSolidQuad(x0, mid - 0.5f, xPos + advance, mid + 0.5f); + } + + xPos += advance; +} + +// Legacy helper used by drawLiteral() only. void Font::renderCharacter(wchar_t c) { - float xOff = c % m_cols * m_charWidth; - float yOff = c / m_cols * m_charHeight; // was m_charWidth — wrong when glyphs aren't square - - float width = charWidths[c] - .01f; float height = m_charHeight - .01f; - - float fontWidth = m_cols * m_charWidth; - float fontHeight = m_rows * m_charHeight; - - const float shear = m_italic ? (height * 0.25f) : 0.0f; - float x0 = xPos, x1 = xPos + width + shear; - float y0 = yPos, y1 = yPos + height; + float x0 = xPos; + float y0 = yPos; + float y1 = yPos + height; Tesselator *t = Tesselator::getInstance(); t->begin(); - t->tex(xOff / fontWidth, (yOff + 7.99f) / fontHeight); - t->vertex(x0, y1, 0.0f); - t->tex((xOff + width) / fontWidth, (yOff + 7.99f) / fontHeight); - t->vertex(x1, y1, 0.0f); - t->tex((xOff + width) / fontWidth, yOff / fontHeight); - t->vertex(x1, y0, 0.0f); - t->tex(xOff / fontWidth, yOff / fontHeight); - t->vertex(x0, y0, 0.0f); + emitCharacterGeometry(c); t->end(); - if (m_bold) - { - float dx = 1.0f; - t->begin(); - t->tex(xOff / fontWidth, (yOff + 7.99f) / fontHeight); - t->vertex(x0 + dx, y1, 0.0f); - t->tex((xOff + width) / fontWidth, (yOff + 7.99f) / fontHeight); - t->vertex(x1 + dx, y1, 0.0f); - t->tex((xOff + width) / fontWidth, yOff / fontHeight); - t->vertex(x1 + dx, y0, 0.0f); - t->tex(xOff / fontWidth, yOff / fontHeight); - t->vertex(x0 + dx, y0, 0.0f); - t->end(); - } - if (m_underline) renderStyleLine(x0, y1 - 1.0f, xPos + static_cast(charWidths[c]), y1); @@ -240,8 +247,8 @@ void Font::renderCharacter(wchar_t c) void Font::drawShadow(const wstring& str, int x, int y, int color) { - draw(str, x + 1, y + 1, color, true); - draw(str, x, y, color, false); + draw(str, x + 1, y + 1, color, true); + draw(str, x, y, color, false); } void Font::drawShadowLiteral(const wstring& str, int x, int y, int color) @@ -289,7 +296,7 @@ static bool isSectionFormatCode(wchar_t ca) return l == L'l' || l == L'o' || l == L'n' || l == L'm' || l == L'r' || l == L'k'; } -void Font::draw(const wstring &str, bool dropShadow) +void Font::draw(const wstring &str, bool dropShadow, int initialColor) { // Bind the texture textures->bindTexture(m_textureLocation); @@ -297,8 +304,11 @@ void Font::draw(const wstring &str, bool dropShadow) m_bold = m_italic = m_underline = m_strikethrough = false; wstring cleanStr = sanitize(str); + int currentColor = initialColor; + Tesselator *t = Tesselator::getInstance(); t->begin(); + t->color(currentColor & 0x00ffffff, (currentColor >> 24) & 255); for (int i = 0; i < static_cast(cleanStr.length()); ++i) { @@ -310,10 +320,8 @@ void Font::draw(const wstring &str, bool dropShadow) wchar_t ca = cleanStr[i+1]; if (!isSectionFormatCode(ca)) { - t->end(); - renderCharacter(167); - renderCharacter(ca); - t->begin(); + addCharacterQuad(167); + addCharacterQuad(ca); i += 1; continue; } @@ -329,7 +337,12 @@ void Font::draw(const wstring &str, bool dropShadow) else if (l == L'o') m_italic = true; else if (l == L'n') m_underline = true; else if (l == L'm') m_strikethrough = true; - else if (l == L'r') m_bold = m_italic = m_underline = m_strikethrough = noise = false; + else if (l == L'r') + { + m_bold = m_italic = m_underline = m_strikethrough = noise = false; + currentColor = initialColor; + t->color(currentColor & 0x00ffffff, (currentColor >> 24) & 255); + } else if (l == L'k') noise = true; } else @@ -337,8 +350,8 @@ void Font::draw(const wstring &str, bool dropShadow) noise = false; if (colorN < 0 || colorN > 15) colorN = 15; if (dropShadow) colorN += 16; - int color = colors[colorN]; - glColor3f((color >> 16) / 255.0F, ((color >> 8) & 255) / 255.0F, (color & 255) / 255.0F); + currentColor = (initialColor & 0xff000000) | colors[colorN]; + t->color(currentColor & 0x00ffffff, (currentColor >> 24) & 255); } i += 1; continue; @@ -371,11 +384,11 @@ void Font::draw(const wstring& str, int x, int y, int color, bool dropShadow) if (dropShadow) // divide RGB by 4, preserve alpha color = (color & 0xfcfcfc) >> 2 | (color & (-1 << 24)); - glColor4f((color >> 16 & 255) / 255.0F, (color >> 8 & 255) / 255.0F, (color & 255) / 255.0F, (color >> 24 & 255) / 255.0F); + glColor4f(1.0F, 1.0F, 1.0F, 1.0F); xPos = x; yPos = y; - draw(str, dropShadow); + draw(str, dropShadow, color); } } @@ -422,9 +435,9 @@ wstring Font::sanitize(const wstring& str) { wstring sb = str; - for (unsigned int i = 0; i < sb.length(); i++) + for (unsigned int i = 0; i < sb.length(); i++) { - if (CharacterExists(sb[i])) + if (CharacterExists(sb[i])) { sb[i] = MapCharacter(sb[i]); } @@ -433,8 +446,8 @@ wstring Font::sanitize(const wstring& str) // If this character isn't supported, just show the first character (empty square box character) sb[i] = 0; } - } - return sb; + } + return sb; } int Font::MapCharacter(wchar_t c) @@ -487,95 +500,95 @@ void Font::drawWordWrap(const wstring &string, int x, int y, int w, int col, boo void Font::drawWordWrapInternal(const wstring& string, int x, int y, int w, int col, bool darken, int h) { - vectorlines = stringSplit(string,L'\n'); - if (lines.size() > 1) + vectorlines = stringSplit(string,L'\n'); + if (lines.size() > 1) { - for ( auto& it : lines ) - { + for ( auto& it : lines ) + { // 4J Stu - Don't draw text that will be partially cutoff/overlap something it shouldn't if( (y + this->wordWrapHeight(it, w)) > h) break; - drawWordWrapInternal(it, x, y, w, col, h); - y += this->wordWrapHeight(it, w); - } - return; - } - vector words = stringSplit(string,L' '); - unsigned int pos = 0; - while (pos < words.size()) + drawWordWrapInternal(it, x, y, w, col, h); + y += this->wordWrapHeight(it, w); + } + return; + } + vector words = stringSplit(string,L' '); + unsigned int pos = 0; + while (pos < words.size()) { - wstring line = words[pos++] + L" "; - while (pos < words.size() && width(line + words[pos]) < w) + wstring line = words[pos++] + L" "; + while (pos < words.size() && width(line + words[pos]) < w) { - line += words[pos++] + L" "; - } - while (width(line) > w) + line += words[pos++] + L" "; + } + while (width(line) > w) { - int l = 0; - while (width(line.substr(0, l + 1)) <= w) + int l = 0; + while (width(line.substr(0, l + 1)) <= w) { - l++; - } - if (trimString(line.substr(0, l)).length() > 0) + l++; + } + if (trimString(line.substr(0, l)).length() > 0) { - draw(line.substr(0, l), x, y, col); - y += 8; - } - line = line.substr(l); + draw(line.substr(0, l), x, y, col); + y += 8; + } + line = line.substr(l); // 4J Stu - Don't draw text that will be partially cutoff/overlap something it shouldn't if( (y + 8) > h) break; - } + } // 4J Stu - Don't draw text that will be partially cutoff/overlap something it shouldn't - if (trimString(line).length() > 0 && !( (y + 8) > h) ) + if (trimString(line).length() > 0 && !( (y + 8) > h) ) { - draw(line, x, y, col); - y += 8; - } - } + draw(line, x, y, col); + y += 8; + } + } } int Font::wordWrapHeight(const wstring& string, int w) { - vector lines = stringSplit(string,L'\n'); - if (lines.size() > 1) + vector lines = stringSplit(string,L'\n'); + if (lines.size() > 1) { - int h = 0; - for ( auto& it : lines ) - { - h += this->wordWrapHeight(it, w); - } - return h; - } + int h = 0; + for ( auto& it : lines ) + { + h += this->wordWrapHeight(it, w); + } + return h; + } vector words = stringSplit(string,L' '); - unsigned int pos = 0; - int y = 0; - while (pos < words.size()) + unsigned int pos = 0; + int y = 0; + while (pos < words.size()) { - wstring line = words[pos++] + L" "; - while (pos < words.size() && width(line + words[pos]) < w) + wstring line = words[pos++] + L" "; + while (pos < words.size() && width(line + words[pos]) < w) { - line += words[pos++] + L" "; - } - while (width(line) > w) + line += words[pos++] + L" "; + } + while (width(line) > w) { - int l = 0; + int l = 0; while (width(line.substr(0, l + 1)) <= w) { - l++; - } - if (trimString(line.substr(0, l)).length() > 0) + l++; + } + if (trimString(line.substr(0, l)).length() > 0) { - y += 8; - } - line = line.substr(l); - } - if (trimString(line).length() > 0) { - y += 8; - } - } - if (y < 8) y += 8; - return y; + y += 8; + } + line = line.substr(l); + } + if (trimString(line).length() > 0) { + y += 8; + } + } + if (y < 8) y += 8; + return y; } diff --git a/Minecraft.Client/Font.h b/Minecraft.Client/Font.h index c78ea678..58bceb4c 100644 --- a/Minecraft.Client/Font.h +++ b/Minecraft.Client/Font.h @@ -38,7 +38,7 @@ private: std::map m_charMap; public: - Font(Options *options, const wstring& name, Textures* textures, bool enforceUnicode, ResourceLocation *textureLocation, int cols, int rows, int charWidth, int charHeight, unsigned short charMap[] = nullptr); + Font(Options *options, const wstring& name, Textures* textures, bool enforceUnicode, ResourceLocation *textureLocation, int cols, int rows, int charWidth, int charHeight, unsigned short charMap[] = nullptr); #ifndef _XBOX // 4J Stu - This dtor clashes with one in xui! We never delete these anyway so take it out for now. Can go back when we have got rid of XUI ~Font(); @@ -48,6 +48,8 @@ public: private: void renderCharacter(wchar_t c); // 4J added void addCharacterQuad(wchar_t c); + void addSolidQuad(float x0, float y0, float x1, float y1); + void emitCharacterGeometry(wchar_t c); void renderStyleLine(float x0, float y0, float x1, float y1); // solid line for underline/strikethrough public: @@ -65,7 +67,7 @@ public: private: wstring reorderBidi(const wstring &str); - void draw(const wstring &str, bool dropShadow); + void draw(const wstring &str, bool dropShadow, int baseColor); void draw(const wstring& str, int x, int y, int color, bool dropShadow); void drawLiteral(const wstring& str, int x, int y, int color); // no § parsing int MapCharacter(wchar_t c); // 4J added