~ubuntu-branches/ubuntu/trusty/rlvm/trusty

« back to all changes in this revision

Viewing changes to src/Systems/Base/TextSystem.cpp

  • Committer: Package Import Robot
  • Author(s): Ying-Chun Liu (PaulLiu)
  • Date: 2013-11-02 02:57:13 UTC
  • mfrom: (10.1.3 sid)
  • Revision ID: package-import@ubuntu.com-20131102025713-yzg31grxr8i7xerh
Tags: 0.13-1
* New upstream release
  - rlvm will now warn on startup when it detects Japanese save data, but
    English patched game files, and offer to reset the save data.
  - Much better support for Little Busters. Most graphical glitches during
    the Little Busters Refrain have been fixed.
  - TCC tone curve effects have been reverse-engineered and implemented
    (thanks to lurkmoar)
  - Sepia scenes (and other graphical filters) should look much better.
  - Simple shake commands implemented (fancy per-layer shaking still
    unimplemented).
  - Make animations smooth: data should be uploaded to the graphics card
    before an animation loop starts, not while the animation loop is
    running.
  - Fixes finding system fonts on Linux
  - Thanks to Elliot Glaysher <glaysher@umich.edu>
* Remove upstreamed patches:
  - debian/patches/002_675426ad62bccf1de10b0ae31dd46331ec47aacb.patch
  - debian/patches/003_5dafabf5448635c4d4526d6e35ea7ec664a27261.patch
  - debian/patches/004_boost-drop-mt.patch
  - debian/patches/005_missing-include.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
65
65
 
66
66
const unsigned int MAX_PAGE_HISTORY = 100;
67
67
 
 
68
const int FULLWIDTH_NUMBER_SIGN = 0xFF03;
 
69
const int FULLWIDTH_A = 0xFF21;
 
70
const int FULLWIDTH_B = 0xFF22;
 
71
const int FULLWIDTH_ZERO = 0xFF10;
 
72
const int FULLWIDTH_NINE = 0xFF19;
 
73
 
68
74
// -----------------------------------------------------------------------
69
75
// TextSystemGlobals
70
76
// -----------------------------------------------------------------------
93
99
      ctrl_key_skip_(true),
94
100
      fast_text_mode_(false),
95
101
      message_no_wait_(false),
 
102
      script_message_no_wait_(false),
96
103
      active_window_(0),
97
104
      is_reading_backlog_(false),
98
105
      current_pageset_(new PageSet),
494
501
 
495
502
boost::shared_ptr<Surface> TextSystem::renderText(
496
503
    const std::string& utf8str, int size, int xspace, int yspace,
497
 
    const RGBColour& colour, RGBColour* shadow_colour) {
 
504
    const RGBColour& colour, RGBColour* shadow_colour,
 
505
    int max_chars_in_line) {
 
506
  const int line_max_width =
 
507
      (max_chars_in_line > 0) ? (size + xspace) * max_chars_in_line :
 
508
      INT_MAX;
 
509
 
498
510
  // On the first pass, we figure out how large of a surface we need for
499
511
  // rendering the text.
500
512
  int current_size = size;
502
514
  int max_width = 0;
503
515
  int current_line_width = 0;
504
516
  int current_line_height = 0;
 
517
  bool should_break = false;
505
518
  std::string::const_iterator it = utf8str.begin();
506
519
  std::string::const_iterator strend = utf8str.end();
507
520
  while (it != strend) {
508
521
    int codepoint = utf8::next(it, strend);
509
522
    bool add_char = true;
 
523
    bool is_emoji = false;
510
524
 
511
525
    if (codepoint == '#') {
512
526
      add_char = false;
513
527
      codepoint = utf8::next(it, strend);
514
528
      switch (codepoint) {
515
 
        // TODO(erg): While playtesting with this new parser, I noticed a '#a'
516
 
        // control code that wasn't mentioned in xclannad's source or in rldev,
517
 
        // but is used in Little Busters.
518
529
        case 'D':
519
530
        case 'd': {
520
 
          total_height += current_line_height + yspace;
521
 
          current_line_height = 0;
 
531
          should_break = true;
522
532
          break;
523
533
        }
524
534
        case 'S':
548
558
          add_char = true;
549
559
        }
550
560
      }
 
561
    } else if (codepoint == FULLWIDTH_NUMBER_SIGN) {
 
562
      // The codepoint is a fullwidth '#'. If the codepoint after this is a
 
563
      // fullwidth 'A' or 'B', followed by two fullwidth digits, we have an
 
564
      // emoji code, and should treat it like a fullwidth space during the
 
565
      // allocation phase.
 
566
      std::string::const_iterator n = it;
 
567
      int next_codepoint = utf8::next(n, strend);
 
568
      if (next_codepoint == FULLWIDTH_A || next_codepoint == FULLWIDTH_B) {
 
569
        int num_one = utf8::next(n, strend);
 
570
        int num_two = utf8::next(n, strend);
 
571
        if (num_one >= FULLWIDTH_ZERO && num_one <= FULLWIDTH_NINE &&
 
572
            num_two >= FULLWIDTH_ZERO && num_two <= FULLWIDTH_NINE) {
 
573
          // This is an emoji mark. We should consume all input so far.
 
574
          it = n;
 
575
          is_emoji = true;
 
576
        }
 
577
      }
551
578
    }
552
579
 
553
 
    if (add_char) {
554
 
      int w = charWidth(current_size, codepoint);
555
 
      // TODO(erg): xspace should be added on the next character add.
556
 
      current_line_width += (w + xspace);
 
580
    int added_width = 0;
 
581
    if (add_char)
 
582
      added_width = charWidth(current_size, codepoint) + xspace;
 
583
    else if (is_emoji)
 
584
      added_width = size + xspace;
 
585
 
 
586
    if (added_width) {
 
587
      if (should_break || current_line_width + added_width > line_max_width) {
 
588
        total_height += current_line_height + yspace;
 
589
        current_line_height = current_size;
 
590
        current_line_width = added_width;
 
591
        should_break = false;
 
592
      } else {
 
593
        current_line_width += added_width;
 
594
        current_line_height = std::max(current_line_height, current_size);
 
595
      }
557
596
 
558
597
      max_width = std::max(max_width, current_line_width);
559
 
      current_line_height = std::max(current_line_height, current_size);
560
598
    }
561
599
  }
562
600
  total_height += current_line_height;
 
601
  should_break = false;
 
602
 
 
603
  // If this text has a shadow, our surface needs to have a final two pixels
 
604
  // added to the bottom and right to accommodate it.
 
605
  if (shadow_colour) {
 
606
    total_height += 2;
 
607
    max_width += 2;
 
608
  }
563
609
 
564
610
  // TODO(erg): Surely there's a way to allocate with something other than
565
611
  // black, right?
578
624
    int codepoint = utf8::next(cur_end, strend);
579
625
    std::string character(it, cur_end);
580
626
    bool add_char = true;
 
627
    bool is_emoji = false;
 
628
    int emoji_id = 0;
 
629
    boost::shared_ptr<const Surface> emoji_surface;
581
630
 
582
631
    if (codepoint == '#') {
583
632
      add_char = false;
585
634
      switch (codepoint) {
586
635
        case 'D':
587
636
        case 'd': {
588
 
          currentX = 0;
589
 
          currentY += current_line_height + yspace;
590
 
          current_line_height = 0;
 
637
          should_break = true;
591
638
          break;
592
639
        }
593
640
        case 'S':
622
669
          add_char = true;
623
670
        }
624
671
      }
 
672
    } else if (codepoint == FULLWIDTH_NUMBER_SIGN) {
 
673
      // The codepoint is a fullwidth '#'. If the codepoint after this is a
 
674
      // fullwidth 'A' or 'B', followed by two fullwidth digits, we have an
 
675
      // emoji code, and should treat it like a fullwidth space during the
 
676
      // allocation phase.
 
677
      std::string::const_iterator n = cur_end;
 
678
      int next_codepoint = utf8::next(n, strend);
 
679
      if (next_codepoint == FULLWIDTH_A || next_codepoint == FULLWIDTH_B) {
 
680
        int num_one = utf8::next(n, strend);
 
681
        int num_two = utf8::next(n, strend);
 
682
        if (num_one >= FULLWIDTH_ZERO && num_one <= FULLWIDTH_NINE &&
 
683
            num_two >= FULLWIDTH_ZERO && num_two <= FULLWIDTH_NINE) {
 
684
          // This is an emoji mark. We should consume all input so far.
 
685
          cur_end = n;
 
686
 
 
687
          // Get the emoji number from the text.
 
688
          num_one -= FULLWIDTH_ZERO;
 
689
          num_two -= FULLWIDTH_ZERO;
 
690
          emoji_id = num_one * 10 + num_two;
 
691
 
 
692
          // Lookup what g00 surface we should use for emoji.
 
693
          emoji_surface = system().graphics().GetEmojiSurface();
 
694
          is_emoji = true;
 
695
          add_char = false;
 
696
        }
 
697
      }
 
698
    }
 
699
 
 
700
    int item_width = 0;
 
701
    if (add_char) {
 
702
      // If we add this character, will we horizontally overflow?
 
703
      item_width = charWidth(current_size, codepoint);
 
704
    } else if (is_emoji) {
 
705
      // Whatever the real size is, we only allocate the incoming size. This
 
706
      // means that if the emoji is larger than |size|, we'll draw text over
 
707
      // it. This is to be bug for bug compatible with RealLive.
 
708
      item_width = size;
 
709
    }
 
710
 
 
711
    if (item_width) {
 
712
      if (should_break || currentX + item_width > max_width) {
 
713
        currentX = 0;
 
714
        currentY += current_line_height + yspace;
 
715
        current_line_height = 0;
 
716
        should_break = false;
 
717
      }
625
718
    }
626
719
 
627
720
    if (add_char) {
634
727
                               surface);
635
728
      currentX += s.width() + xspace;
636
729
      current_line_height = std::max(current_line_height, current_size);
 
730
    } else if (is_emoji) {
 
731
      if (emoji_surface) {
 
732
        // Emoji surfaces don't have internal pattnos. Instead, assume that
 
733
        // icons are square and laid out to the right, sort of like mouse
 
734
        // cursors.
 
735
        int height = emoji_surface->size().height();
 
736
        Rect src = Rect(height * emoji_id, 0, Size(height, height));
 
737
        Rect dst = Rect(currentX, currentY, Size(height, height));
 
738
        emoji_surface->blitToSurface(*surface, src, dst, 255, false);
 
739
      }
 
740
 
 
741
      currentX += size + xspace;
 
742
      current_line_height = std::max(current_line_height, current_size);
637
743
    }
638
744
 
639
745
    it = cur_end;
644
750
 
645
751
void TextSystem::reset() {
646
752
  is_reading_backlog_ = false;
 
753
  script_message_no_wait_ = false;
647
754
 
648
755
  current_pageset_ = std::auto_ptr<PageSet>(new PageSet);
649
756
  previous_page_sets_.clear();