the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
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