the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at master 617 lines 15 kB view raw
1#include "stdafx.h" 2#include "Textures.h" 3#include "Font.h" 4#include "Options.h" 5#include "Tesselator.h" 6#include "ResourceLocation.h" 7#include "..\Minecraft.World\IntBuffer.h" 8#include "..\Minecraft.World\net.minecraft.h" 9#include "..\Minecraft.World\StringHelpers.h" 10#include "..\Minecraft.World\Random.h" 11 12Font::Font(Options *options, const wstring& name, Textures* textures, bool enforceUnicode, ResourceLocation *textureLocation, int cols, int rows, int charWidth, int charHeight, unsigned short charMap[]/* = nullptr */) : textures(textures) 13{ 14 int charC = cols * rows; // Number of characters in the font 15 16 charWidths = new int[charC]; 17 18 // 4J - added initialisers 19 memset(charWidths, 0, charC); 20 21 enforceUnicodeSheet = false; 22 bidirectional = false; 23 xPos = yPos = 0.0f; 24 25 // Set up member variables 26 m_cols = cols; 27 m_rows = rows; 28 m_charWidth = charWidth; 29 m_charHeight = charHeight; 30 m_textureLocation = textureLocation; 31 32 // Build character map 33 if (charMap != NULL) 34 { 35 for(int i = 0; i < charC; i++) 36 { 37 m_charMap.insert(std::make_pair(charMap[i], i)); 38 } 39 } 40 41 random = new Random(); 42 43 // Load the image 44 BufferedImage *img = textures->readImage(textureLocation->getTexture(), name); 45 46 /* - 4J - TODO 47 try { 48 img = ImageIO.read(Textures.class.getResourceAsStream(name)); 49 } catch (IOException e) { 50 throw new RuntimeException(e); 51 } 52 */ 53 54 int w = img->getWidth(); 55 int h = img->getHeight(); 56 intArray rawPixels(w * h); 57 img->getRGB(0, 0, w, h, rawPixels, 0, w); 58 59 for (int i = 0; i < charC; i++) 60 { 61 int xt = i % m_cols; 62 int yt = i / m_cols; 63 64 int x = 7; 65 for (; x >= 0; x--) 66 { 67 int xPixel = xt * 8 + x; 68 bool emptyColumn = true; 69 for (int y = 0; y < 8 && emptyColumn; y++) 70 { 71 int yPixel = (yt * 8 + y) * w; 72 bool emptyPixel = (rawPixels[xPixel + yPixel] >> 24) == 0; // Check the alpha value 73 if (!emptyPixel) emptyColumn = false; 74 } 75 if (!emptyColumn) 76 { 77 break; 78 } 79 } 80 81 if (i == ' ') x = 4 - 2; 82 charWidths[i] = x + 2; 83 } 84 85 delete img; 86 87 // calculate colors 88 for (int colorN = 0; colorN < 32; ++colorN) 89 { 90 int var10 = (colorN >> 3 & 1) * 85; 91 int red = (colorN >> 2 & 1) * 170 + var10; 92 int green = (colorN >> 1 & 1) * 170 + var10; 93 int blue = (colorN >> 0 & 1) * 170 + var10; 94 95 if (colorN == 6) 96 { 97 red += 85; 98 } 99 100 if (options->anaglyph3d) 101 { 102 int tmpRed = (red * 30 + green * 59 + blue * 11) / 100; 103 int tmpGreen = (red * 30 + green * 70) / 100; 104 int tmpBlue = (red * 30 + blue * 70) / 100; 105 red = tmpRed; 106 green = tmpGreen; 107 blue = tmpBlue; 108 } 109 110 if (colorN >= 16) 111 { 112 red /= 4; 113 green /= 4; 114 blue /= 4; 115 } 116 117 colors[colorN] = (red & 255) << 16 | (green & 255) << 8 | (blue & 255); 118 } 119} 120 121#ifndef _XBOX 122// 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 123Font::~Font() 124{ 125 delete[] charWidths; 126} 127#endif 128 129void Font::renderCharacter(wchar_t c) 130{ 131 float xOff = c % m_cols * m_charWidth; 132 float yOff = c / m_cols * m_charWidth; 133 134 float width = charWidths[c] - .01f; 135 float height = m_charHeight - .01f; 136 137 float fontWidth = m_cols * m_charWidth; 138 float fontHeight = m_rows * m_charHeight; 139 140 Tesselator *t = Tesselator::getInstance(); 141 // 4J Stu - Changed to a quad so that we can use within a command buffer 142#if 1 143 t->begin(); 144 t->tex(xOff / fontWidth, (yOff + 7.99f) / fontHeight); 145 t->vertex(xPos, yPos + height, 0.0f); 146 147 t->tex((xOff + width) / fontWidth, (yOff + 7.99f) / fontHeight); 148 t->vertex(xPos + width, yPos + height, 0.0f); 149 150 t->tex((xOff + width) / fontWidth, yOff / fontHeight); 151 t->vertex(xPos + width, yPos, 0.0f); 152 153 t->tex(xOff / fontWidth, yOff / fontHeight); 154 t->vertex(xPos, yPos, 0.0f); 155 156 t->end(); 157#else 158 t->begin(GL_TRIANGLE_STRIP); 159 t->tex(xOff / 128.0F, yOff / 128.0F); 160 t->vertex(xPos, yPos, 0.0f); 161 t->tex(xOff / 128.0F, (yOff + 7.99f) / 128.0F); 162 t->vertex(xPos, yPos + 7.99f, 0.0f); 163 t->tex((xOff + width) / 128.0F, yOff / 128.0F); 164 t->vertex(xPos + width, yPos, 0.0f); 165 t->tex((xOff + width) / 128.0F, (yOff + 7.99f) / 128.0F); 166 t->vertex(xPos + width, yPos + 7.99f, 0.0f); 167 t->end(); 168#endif 169 170 xPos += (float) charWidths[c]; 171} 172 173void Font::drawShadow(const wstring& str, int x, int y, int color) 174{ 175 draw(str, x + 1, y + 1, color, true); 176 draw(str, x, y, color, false); 177} 178 179void Font::drawShadowWordWrap(const wstring &str, int x, int y, int w, int color, int h) 180{ 181 drawWordWrapInternal(str, x + 1, y + 1, w, color, true, h); 182 drawWordWrapInternal(str, x, y, w, color, h); 183} 184 185void Font::draw(const wstring& str, int x, int y, int color) 186{ 187 draw(str, x, y, color, false); 188} 189 190wstring Font::reorderBidi(const wstring &str) 191{ 192 // 4J Not implemented 193 return str; 194} 195 196void Font::draw(const wstring &str, bool dropShadow) 197{ 198 // Bind the texture 199 textures->bindTexture(m_textureLocation); 200 201 bool noise = false; 202 wstring cleanStr = sanitize(str); 203 204 for (int i = 0; i < (int)cleanStr.length(); ++i) 205 { 206 // Map character 207 wchar_t c = cleanStr.at(i); 208 209 if (c == 167 && i + 1 < cleanStr.length()) 210 { 211 // 4J - following block was: 212 // int colorN = L"0123456789abcdefk".indexOf(str.toLowerCase().charAt(i + 1)); 213 wchar_t ca = cleanStr[i+1]; 214 int colorN = 16; 215 if(( ca >= L'0' ) && (ca <= L'9')) colorN = ca - L'0'; 216 else if(( ca >= L'a' ) && (ca <= L'f')) colorN = (ca - L'a') + 10; 217 else if(( ca >= L'A' ) && (ca <= L'F')) colorN = (ca - L'A') + 10; 218 219 if (colorN == 16) 220 { 221 noise = true; 222 } 223 else 224 { 225 noise = false; 226 if (colorN < 0 || colorN > 15) colorN = 15; 227 228 if (dropShadow) colorN += 16; 229 230 int color = colors[colorN]; 231 glColor3f((color >> 16) / 255.0F, ((color >> 8) & 255) / 255.0F, (color & 255) / 255.0F); 232 } 233 234 235 i += 1; 236 continue; 237 } 238 239 // "noise" for crazy splash screen message 240 if (noise) 241 { 242 int newc; 243 do 244 { 245 newc = random->nextInt(SharedConstants::acceptableLetters.length()); 246 } while (charWidths[c + 32] != charWidths[newc + 32]); 247 c = newc; 248 } 249 250 renderCharacter(c); 251 } 252} 253 254void Font::draw(const wstring& str, int x, int y, int color, bool dropShadow) 255{ 256 if (!str.empty()) 257 { 258 if ((color & 0xFC000000) == 0) color |= 0xFF000000; // force alpha 259 // if not set 260 261 if (dropShadow) // divide RGB by 4, preserve alpha 262 color = (color & 0xfcfcfc) >> 2 | (color & (-1 << 24)); 263 264 glColor4f((color >> 16 & 255) / 255.0F, (color >> 8 & 255) / 255.0F, (color & 255) / 255.0F, (color >> 24 & 255) / 255.0F); 265 266 xPos = x; 267 yPos = y; 268 draw(str, dropShadow); 269 } 270} 271 272int Font::width(const wstring& str) 273{ 274 wstring cleanStr = sanitize(str); 275 276 if (cleanStr == L"") return 0; // 4J - was NULL comparison 277 int len = 0; 278 279 for (int i = 0; i < cleanStr.length(); ++i) 280 { 281 wchar_t c = cleanStr.at(i); 282 283 if(c == 167) 284 { 285 // Ignore the character used to define coloured text 286 ++i; 287 } 288 else 289 { 290 len += charWidths[c]; 291 } 292 } 293 294 return len; 295} 296 297wstring Font::sanitize(const wstring& str) 298{ 299 wstring sb = str; 300 301 for (unsigned int i = 0; i < sb.length(); i++) 302 { 303 if (CharacterExists(sb[i])) 304 { 305 sb[i] = MapCharacter(sb[i]); 306 } 307 else 308 { 309 // If this character isn't supported, just show the first character (empty square box character) 310 sb[i] = 0; 311 } 312 } 313 return sb; 314} 315 316int Font::MapCharacter(wchar_t c) 317{ 318 if (!m_charMap.empty()) 319 { 320 // Don't map space character 321 return c == ' ' ? c : m_charMap[c]; 322 } 323 else 324 { 325 return c; 326 } 327} 328 329bool Font::CharacterExists(wchar_t c) 330{ 331 if (!m_charMap.empty()) 332 { 333 return m_charMap.find(c) != m_charMap.end(); 334 } 335 else 336 { 337 return c >= 0 && c <= m_rows*m_cols; 338 } 339} 340 341void Font::drawWordWrap(const wstring &string, int x, int y, int w, int col, int h) 342{ 343 //if (bidirectional) 344 //{ 345 // string = reorderBidi(string); 346 //} 347 drawWordWrapInternal(string, x, y, w, col, h); 348} 349 350void Font::drawWordWrapInternal(const wstring &string, int x, int y, int w, int col, int h) 351{ 352 drawWordWrapInternal(string, x, y, w, col, false, h); 353} 354 355void Font::drawWordWrap(const wstring &string, int x, int y, int w, int col, bool darken, int h) 356{ 357 //if (bidirectional) 358 //{ 359 // string = reorderBidi(string); 360 //} 361 drawWordWrapInternal(string, x, y, w, col, darken, h); 362} 363 364void Font::drawWordWrapInternal(const wstring& string, int x, int y, int w, int col, bool darken, int h) 365{ 366 vector<wstring>lines = stringSplit(string,L'\n'); 367 if (lines.size() > 1) 368 { 369 AUTO_VAR(itEnd, lines.end()); 370 for (AUTO_VAR(it, lines.begin()); it != itEnd; it++) 371 { 372 // 4J Stu - Don't draw text that will be partially cutoff/overlap something it shouldn't 373 if( (y + this->wordWrapHeight(*it, w)) > h) break; 374 drawWordWrapInternal(*it, x, y, w, col, h); 375 y += this->wordWrapHeight(*it, w); 376 } 377 return; 378 } 379 vector<wstring> words = stringSplit(string,L' '); 380 unsigned int pos = 0; 381 while (pos < words.size()) 382 { 383 wstring line = words[pos++] + L" "; 384 while (pos < words.size() && width(line + words[pos]) < w) 385 { 386 line += words[pos++] + L" "; 387 } 388 while (width(line) > w) 389 { 390 int l = 0; 391 while (width(line.substr(0, l + 1)) <= w) 392 { 393 l++; 394 } 395 if (trimString(line.substr(0, l)).length() > 0) 396 { 397 draw(line.substr(0, l), x, y, col); 398 y += 8; 399 } 400 line = line.substr(l); 401 402 // 4J Stu - Don't draw text that will be partially cutoff/overlap something it shouldn't 403 if( (y + 8) > h) break; 404 } 405 // 4J Stu - Don't draw text that will be partially cutoff/overlap something it shouldn't 406 if (trimString(line).length() > 0 && !( (y + 8) > h) ) 407 { 408 draw(line, x, y, col); 409 y += 8; 410 } 411 } 412 413} 414 415int Font::wordWrapHeight(const wstring& string, int w) 416{ 417 vector<wstring> lines = stringSplit(string,L'\n'); 418 if (lines.size() > 1) 419 { 420 int h = 0; 421 AUTO_VAR(itEnd, lines.end()); 422 for (AUTO_VAR(it, lines.begin()); it != itEnd; it++) 423 { 424 h += this->wordWrapHeight(*it, w); 425 } 426 return h; 427 } 428 vector<wstring> words = stringSplit(string,L' '); 429 unsigned int pos = 0; 430 int y = 0; 431 while (pos < words.size()) 432 { 433 wstring line = words[pos++] + L" "; 434 while (pos < words.size() && width(line + words[pos]) < w) 435 { 436 line += words[pos++] + L" "; 437 } 438 while (width(line) > w) 439 { 440 int l = 0; 441 while (width(line.substr(0, l + 1)) <= w) 442 { 443 l++; 444 } 445 if (trimString(line.substr(0, l)).length() > 0) 446 { 447 y += 8; 448 } 449 line = line.substr(l); 450 } 451 if (trimString(line).length() > 0) { 452 y += 8; 453 } 454 } 455 if (y < 8) y += 8; 456 return y; 457 458} 459 460void Font::setEnforceUnicodeSheet(bool enforceUnicodeSheet) 461{ 462 this->enforceUnicodeSheet = enforceUnicodeSheet; 463} 464 465void Font::setBidirectional(bool bidirectional) 466{ 467 this->bidirectional = bidirectional; 468} 469 470bool Font::AllCharactersValid(const wstring &str) 471{ 472 for (int i = 0; i < (int)str.length(); ++i) 473 { 474 wchar_t c = str.at(i); 475 476 if (c == 167 && i + 1 < str.length()) 477 { 478 // skip special color setting 479 i += 1; 480 continue; 481 } 482 483 int index = SharedConstants::acceptableLetters.find(c); 484 485 if ((c != ' ') && !(index > 0 && !enforceUnicodeSheet)) 486 { 487 return false; 488 } 489 } 490 return true; 491} 492 493// Not in use 494/*// 4J - this code is lifted from #if 0 section above, so that we can directly create what would have gone in each of our 256 + 32 command buffers 495void Font::renderFakeCB(IntBuffer *ib) 496{ 497 Tesselator *t = Tesselator::getInstance(); 498 499 int i; 500 501 for(unsigned int j = 0; j < ib->limit(); j++) 502 { 503 int cb = ib->get(j); 504 505 if( cb < 256 ) 506 { 507 i = cb; 508 t->begin(); 509 int ix = i % 16 * 8; 510 int iy = i / 16 * 8; 511 // float s = 7.99f; 512 float s = 7.99f; 513 514 float uo = (0.0f) / 128.0f; 515 float vo = (0.0f) / 128.0f; 516 517 t->vertexUV((float)(0), (float)( 0 + s), (float)( 0), (float)( ix / 128.0f + uo), (float)( (iy + s) / 128.0f + vo)); 518 t->vertexUV((float)(0 + s), (float)( 0 + s), (float)( 0), (float)( (ix + s) / 128.0f + uo), (float)( (iy + s) / 128.0f + vo)); 519 t->vertexUV((float)(0 + s), (float)( 0), (float)( 0), (float)( (ix + s) / 128.0f + uo), (float)( iy / 128.0f + vo)); 520 t->vertexUV((float)(0), (float)( 0), (float)( 0), (float)( ix / 128.0f + uo), (float)( iy / 128.0f + vo)); 521 // target.colorBlit(texture, x + xo, y, color, ix, iy, 522 // charWidths[chars[i]], 8); 523 t->end(); 524 525 glTranslatef((float)charWidths[i], 0, 0); 526 } 527 else 528 { 529 i = cb - 256; 530 531 int br = ((i >> 3) & 1) * 0x55; 532 int r = ((i >> 2) & 1) * 0xaa + br; 533 int g = ((i >> 1) & 1) * 0xaa + br; 534 int b = ((i >> 0) & 1) * 0xaa + br; 535 if (i == 6) 536 { 537 r += 0x55; 538 } 539 bool darken = i >= 16; 540 541 // color = r << 16 | g << 8 | b; 542 if (darken) 543 { 544 r /= 4; 545 g /= 4; 546 b /= 4; 547 } 548 glColor3f(r / 255.0f, g / 255.0f, b / 255.0f); 549 } 550 } 551} 552 553void Font::loadUnicodePage(int page) 554{ 555 wchar_t fileName[25]; 556 //String fileName = String.format("/1_2_2/font/glyph_%02X.png", page); 557 swprintf(fileName,25,L"/1_2_2/font/glyph_%02X.png",page); 558 BufferedImage *image = new BufferedImage(fileName); 559 //try 560 //{ 561 // image = ImageIO.read(Textures.class.getResourceAsStream(fileName.toString())); 562 //} 563 //catch (IOException e) 564 //{ 565 // throw new RuntimeException(e); 566 //} 567 568 unicodeTexID[page] = textures->getTexture(image); 569 lastBoundTexture = unicodeTexID[page]; 570} 571 572void Font::renderUnicodeCharacter(wchar_t c) 573{ 574 if (unicodeWidth[c] == 0) 575 { 576 // System.out.println("no-width char " + c); 577 return; 578 } 579 580 int page = c / 256; 581 582 if (unicodeTexID[page] == 0) loadUnicodePage(page); 583 584 if (lastBoundTexture != unicodeTexID[page]) 585 { 586 glBindTexture(GL_TEXTURE_2D, unicodeTexID[page]); 587 lastBoundTexture = unicodeTexID[page]; 588 } 589 590 // first column with non-trans pixels 591 int firstLeft = unicodeWidth[c] >> 4; 592 // last column with non-trans pixels 593 int firstRight = unicodeWidth[c] & 0xF; 594 595 float left = firstLeft; 596 float right = firstRight + 1; 597 598 float xOff = c % 16 * 16 + left; 599 float yOff = (c & 0xFF) / 16 * 16; 600 float width = right - left - .02f; 601 602 Tesselator *t = Tesselator::getInstance(); 603 t->begin(GL_TRIANGLE_STRIP); 604 t->tex(xOff / 256.0F, yOff / 256.0F); 605 t->vertex(xPos, yPos, 0.0f); 606 t->tex(xOff / 256.0F, (yOff + 15.98f) / 256.0F); 607 t->vertex(xPos, yPos + 7.99f, 0.0f); 608 t->tex((xOff + width) / 256.0F, yOff / 256.0F); 609 t->vertex(xPos + width / 2, yPos, 0.0f); 610 t->tex((xOff + width) / 256.0F, (yOff + 15.98f) / 256.0F); 611 t->vertex(xPos + width / 2, yPos + 7.99f, 0.0f); 612 t->end(); 613 614 xPos += (right - left) / 2 + 1; 615} 616*/ 617