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

« back to all changes in this revision

Viewing changes to src/Systems/Base/GraphicsSystem.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:
27
27
 
28
28
#include "Systems/Base/GraphicsSystem.hpp"
29
29
 
 
30
#include <iostream>
30
31
#include <algorithm>
31
32
#include <boost/algorithm/string.hpp>
32
33
#include <boost/archive/text_iarchive.hpp>
33
34
#include <boost/archive/text_oarchive.hpp>
 
35
#include <boost/bind.hpp>
34
36
#include <boost/lexical_cast.hpp>
35
37
#include <boost/serialization/deque.hpp>
36
38
#include <boost/serialization/scoped_ptr.hpp>
37
39
#include <boost/serialization/vector.hpp>
 
40
#include <boost/tuple/tuple.hpp>
 
41
#include <boost/tuple/tuple_comparison.hpp>
38
42
#include <deque>
39
43
#include <iterator>
40
44
#include <list>
41
45
#include <sstream>
42
46
#include <string>
 
47
#include <utility>
43
48
#include <vector>
44
49
 
45
50
#include "base/notification_service.h"
51
56
#include "Modules/Module_Grp.hpp"
52
57
#include "Systems/Base/AnmGraphicsObjectData.hpp"
53
58
#include "Systems/Base/CGMTable.hpp"
 
59
#include "Systems/Base/EventSystem.hpp"
54
60
#include "Systems/Base/GraphicsObject.hpp"
55
61
#include "Systems/Base/GraphicsObjectData.hpp"
56
62
#include "Systems/Base/GraphicsObjectOfFile.hpp"
57
63
#include "Systems/Base/GraphicsStackFrame.hpp"
 
64
#include "Systems/Base/HIKRenderer.hpp"
58
65
#include "Systems/Base/HIKScript.hpp"
59
66
#include "Systems/Base/MouseCursor.hpp"
 
67
#include "Systems/Base/ObjectMutator.hpp"
60
68
#include "Systems/Base/ObjectSettings.hpp"
61
69
#include "Systems/Base/Surface.hpp"
62
70
#include "Systems/Base/System.hpp"
67
75
#include "libReallive/gameexe.h"
68
76
#include "libReallive/expression.h"
69
77
 
 
78
using boost::bind;
70
79
using boost::iends_with;
71
80
using boost::lexical_cast;
 
81
using std::cerr;
72
82
using std::cout;
73
83
using std::endl;
74
84
using std::fill;
 
85
using std::for_each;
75
86
using std::ostringstream;
76
87
using std::vector;
77
88
 
155
166
  : show_object_1(false), show_object_2(false), show_weather(false),
156
167
    skip_animations(0),
157
168
    screen_mode(1),
158
 
    cg_table() {
 
169
    cg_table(),
 
170
    tone_curves() {
159
171
}
160
172
 
161
173
GraphicsSystemGlobals::GraphicsSystemGlobals(Gameexe& gameexe)
164
176
      show_weather(gameexe("INIT_WEATHER_ONOFF_MOD").to_int(0) ? 0 : 1),
165
177
      skip_animations(0),
166
178
      screen_mode(1),
167
 
      cg_table(gameexe) {
 
179
      cg_table(gameexe),
 
180
      tone_curves(gameexe) {
168
181
}
169
182
 
170
183
// -----------------------------------------------------------------------
217
230
  : screen_update_mode_(SCREENUPDATEMODE_AUTOMATIC),
218
231
    background_type_(BACKGROUND_DC0),
219
232
    screen_needs_refresh_(false),
 
233
    object_state_dirty_(false),
220
234
    is_responsible_for_update_(true),
221
235
    display_subtitle_(gameexe("SUBTITLE").to_int(0)),
222
236
    hide_interface_(false),
223
237
    globals_(gameexe),
 
238
    time_at_last_queue_change_(0),
224
239
    graphics_object_settings_(new GraphicsObjectSettings(gameexe)),
225
240
    graphics_object_impl_(new GraphicsObjectImpl(
226
241
        graphics_object_settings_->objects_in_a_layer)),
227
242
    use_custom_mouse_cursor_(gameexe("MOUSE_CURSOR").exists()),
228
243
    show_cursor_from_bytecode_(true),
229
244
    cursor_(gameexe("MOUSE_CURSOR").to_int(0)),
230
 
    system_(system) {}
 
245
    system_(system),
 
246
    preloaded_hik_scripts_(32),
 
247
    preloaded_g00_(256),
 
248
    image_cache_(10) {}
231
249
 
232
250
// -----------------------------------------------------------------------
233
251
 
281
299
 
282
300
// -----------------------------------------------------------------------
283
301
 
 
302
void GraphicsSystem::QueueShakeSpec(int spec) {
 
303
  Gameexe& gameexe = system().gameexe();
 
304
 
 
305
  if (gameexe("SHAKE", spec).exists()) {
 
306
    vector<int> spec_vector = gameexe("SHAKE", spec).to_intVector();
 
307
 
 
308
    int x, y, time;
 
309
    vector<int>::const_iterator it = spec_vector.begin();
 
310
    while (it != spec_vector.end()) {
 
311
      x = *it++;
 
312
      if (it != spec_vector.end()) {
 
313
        y = *it++;
 
314
        if (it != spec_vector.end()) {
 
315
          time = *it++;
 
316
          screen_shake_queue_.push(std::make_pair(Point(x, y), time));
 
317
        }
 
318
      }
 
319
    }
 
320
 
 
321
    forceRefresh();
 
322
    time_at_last_queue_change_ = system().event().getTicks();
 
323
  }
 
324
}
 
325
 
 
326
// -----------------------------------------------------------------------
 
327
 
 
328
Point GraphicsSystem::GetScreenOrigin() {
 
329
  if (screen_shake_queue_.empty()) {
 
330
    return Point(0, 0);
 
331
  } else {
 
332
    return screen_shake_queue_.front().first;
 
333
  }
 
334
}
 
335
 
 
336
// -----------------------------------------------------------------------
 
337
 
 
338
bool GraphicsSystem::IsShaking() const {
 
339
  return !screen_shake_queue_.empty();
 
340
}
 
341
 
 
342
// -----------------------------------------------------------------------
 
343
 
 
344
int GraphicsSystem::CurrentShakingFrameTime() const {
 
345
  if (screen_shake_queue_.empty()) {
 
346
    return 10;
 
347
  } else {
 
348
    return screen_shake_queue_.front().second;
 
349
  }
 
350
}
 
351
 
 
352
 
 
353
// -----------------------------------------------------------------------
 
354
 
284
355
int GraphicsSystem::useCustomCursor() {
285
356
  return use_custom_mouse_cursor_ &&
286
357
      system().gameexe()("MOUSE_CURSOR", cursor_, "NAME").to_string("") != "";
355
426
 
356
427
// -----------------------------------------------------------------------
357
428
 
358
 
void GraphicsSystem::setHikScript(HIKScript* script) {
359
 
  hik_script_.reset(script);
 
429
void GraphicsSystem::setHikRenderer(HIKRenderer* renderer) {
 
430
  hik_renderer_.reset(renderer);
360
431
}
361
432
 
362
433
// -----------------------------------------------------------------------
443
514
 
444
515
// -----------------------------------------------------------------------
445
516
 
446
 
// Default implementations for some functions (which probably have
447
 
// default implementations because I'm lazy, and these really should
448
 
// be pure virtual)
449
 
void GraphicsSystem::beginFrame() { }
450
 
void GraphicsSystem::endFrame() { }
451
 
 
452
517
void GraphicsSystem::refresh(std::ostream* tree) {
453
518
  beginFrame();
454
519
  drawFrame(tree);
473
538
      break;
474
539
    }
475
540
    case BACKGROUND_HIK: {
476
 
      if (hik_script_) {
477
 
        hik_script_->render(tree);
 
541
      if (hik_renderer_) {
 
542
        hik_renderer_->render(tree);
478
543
      } else {
479
544
        getHaikei()->renderToScreen(screenRect(), screenRect(), 255);
480
545
        if (tree) {
481
 
          *tree << "[Haikei bitmap]";
 
546
          *tree << "[Haikei bitmap: " << default_bgr_name_ << "]" << endl;
482
547
        }
483
548
      }
484
549
    }
491
556
    system().text().render(tree);
492
557
}
493
558
 
 
559
// -----------------------------------------------------------------------
 
560
 
494
561
void GraphicsSystem::executeGraphicsSystem(RLMachine& machine) {
495
 
  if (hik_script_ && background_type_ == BACKGROUND_HIK)
496
 
    hik_script_->execute(machine);
 
562
  // Check to see if any of the graphics objects are reporting that
 
563
  // they want to force a redraw
 
564
  for_each(foregroundObjects().allocated_begin(),
 
565
           foregroundObjects().allocated_end(),
 
566
           bind(&GraphicsObject::execute, _1, boost::ref(machine)));
 
567
 
 
568
  if (mouse_cursor_)
 
569
    mouse_cursor_->execute(system());
 
570
 
 
571
  if (hik_renderer_ && background_type_ == BACKGROUND_HIK)
 
572
    hik_renderer_->execute(machine);
 
573
 
 
574
  // Possibly update the screen shaking state
 
575
  if (!screen_shake_queue_.empty()) {
 
576
    unsigned int now = system().event().getTicks();
 
577
    unsigned int accumulated_ticks = now - time_at_last_queue_change_;
 
578
    while (!screen_shake_queue_.empty() &&
 
579
           accumulated_ticks > screen_shake_queue_.front().second) {
 
580
      int frame_ticks = screen_shake_queue_.front().second;
 
581
      accumulated_ticks -= frame_ticks;
 
582
      time_at_last_queue_change_ += frame_ticks;
 
583
      screen_shake_queue_.pop();
 
584
      forceRefresh();
 
585
    }
 
586
  }
497
587
}
498
588
 
499
589
// -----------------------------------------------------------------------
502
592
  clearAllObjects();
503
593
  clearAllDCs();
504
594
 
505
 
  hik_script_.reset();
 
595
  preloaded_hik_scripts_.clear();
 
596
  preloaded_g00_.clear();
 
597
  hik_renderer_.reset();
506
598
  background_type_ = BACKGROUND_DC0;
507
599
 
508
600
  // Reset the cursor
518
610
  hide_interface_ = false;
519
611
}
520
612
 
 
613
boost::shared_ptr<const Surface> GraphicsSystem::GetEmojiSurface() {
 
614
  GameexeFilteringIterator it = system().gameexe().filtering_begin("E_MOJI.");
 
615
  GameexeFilteringIterator end = system().gameexe().filtering_end();
 
616
  for (; it != end; ++it) {
 
617
    // Try to interpret each key as a filename.
 
618
    std::string file_name = it->to_string("");
 
619
    boost::shared_ptr<const Surface> surface = getSurfaceNamed(file_name);
 
620
    if (surface)
 
621
      return surface;
 
622
  }
 
623
 
 
624
  return boost::shared_ptr<const Surface>();
 
625
}
 
626
 
 
627
void GraphicsSystem::PreloadHIKScript(
 
628
    System& system,
 
629
    int slot,
 
630
    const std::string& name,
 
631
    const boost::filesystem::path& file_path) {
 
632
  HIKScript* script = new HIKScript(system, file_path);
 
633
  script->EnsureUploaded();
 
634
 
 
635
  preloaded_hik_scripts_[slot] = std::make_pair(
 
636
      name, boost::shared_ptr<HIKScript>(script));
 
637
}
 
638
 
 
639
void GraphicsSystem::ClearPreloadedHIKScript(int slot) {
 
640
  preloaded_hik_scripts_[slot] =
 
641
      std::make_pair("", boost::shared_ptr<HIKScript>());
 
642
}
 
643
 
 
644
void GraphicsSystem::ClearAllPreloadedHIKScripts() {
 
645
  preloaded_hik_scripts_.clear();
 
646
}
 
647
 
 
648
boost::shared_ptr<HIKScript> GraphicsSystem::GetHIKScript(
 
649
    System& system,
 
650
    const std::string& name,
 
651
    const boost::filesystem::path& file_path) {
 
652
  AllocatedLazyArrayIterator<HIKArrayItem> it =
 
653
      preloaded_hik_scripts_.allocated_begin();
 
654
  AllocatedLazyArrayIterator<HIKArrayItem> end =
 
655
      preloaded_hik_scripts_.allocated_end();
 
656
  for (; it != end; ++it) {
 
657
    if (it->first == name)
 
658
      return it->second;
 
659
  }
 
660
 
 
661
  return boost::shared_ptr<HIKScript>(new HIKScript(system, file_path));
 
662
}
 
663
 
 
664
void GraphicsSystem::PreloadG00(int slot, const std::string& name) {
 
665
  // We first check our implicit cache just in case so we don't load it twice.
 
666
  boost::shared_ptr<const Surface> surface = image_cache_.fetch(name);
 
667
  if (!surface)
 
668
    surface = loadSurfaceFromFile(name);
 
669
 
 
670
  if (surface)
 
671
    surface->EnsureUploaded();
 
672
 
 
673
  preloaded_g00_[slot] = std::make_pair(name, surface);
 
674
}
 
675
 
 
676
void GraphicsSystem::ClearPreloadedG00(int slot) {
 
677
  preloaded_g00_[slot] =
 
678
      std::make_pair("", boost::shared_ptr<const Surface>());
 
679
}
 
680
 
 
681
void GraphicsSystem::ClearAllPreloadedG00() {
 
682
  preloaded_g00_.clear();
 
683
}
 
684
 
 
685
boost::shared_ptr<const Surface> GraphicsSystem::GetPreloadedG00(
 
686
    const std::string& name) {
 
687
  AllocatedLazyArrayIterator<G00ArrayItem> it =
 
688
      preloaded_g00_.allocated_begin();
 
689
  AllocatedLazyArrayIterator<G00ArrayItem> end =
 
690
      preloaded_g00_.allocated_end();
 
691
  for (; it != end; ++it) {
 
692
    if (it->first == name)
 
693
      return it->second;
 
694
  }
 
695
 
 
696
  return boost::shared_ptr<const Surface>();
 
697
}
 
698
 
521
699
// -----------------------------------------------------------------------
522
700
 
523
 
boost::shared_ptr<Surface> GraphicsSystem::loadSurfaceFromFile(
 
701
boost::shared_ptr<const Surface> GraphicsSystem::getSurfaceNamedAndMarkViewed(
524
702
  RLMachine& machine, const std::string& short_filename) {
525
703
  // Record that we viewed this CG.
526
704
  cgTable().setViewed(machine, short_filename);
527
705
 
528
 
  return loadNonCGSurfaceFromFile(short_filename);
 
706
  return getSurfaceNamed(short_filename);
 
707
}
 
708
 
 
709
// -----------------------------------------------------------------------
 
710
 
 
711
boost::shared_ptr<const Surface> GraphicsSystem::getSurfaceNamed(
 
712
    const std::string& short_filename) {
 
713
  // Check if this is in the script controlled cache.
 
714
  boost::shared_ptr<const Surface> cached_surface =
 
715
      GetPreloadedG00(short_filename);
 
716
  if (cached_surface)
 
717
    return cached_surface;
 
718
 
 
719
  // First check to see if this surface is already in our internal cache
 
720
  cached_surface = image_cache_.fetch(short_filename);
 
721
  if (cached_surface)
 
722
    return cached_surface;
 
723
 
 
724
  boost::shared_ptr<const Surface> surface_to_ret =
 
725
      loadSurfaceFromFile(short_filename);
 
726
  image_cache_.insert(short_filename, surface_to_ret);
 
727
  return surface_to_ret;
529
728
}
530
729
 
531
730
// -----------------------------------------------------------------------
577
776
 
578
777
// -----------------------------------------------------------------------
579
778
 
 
779
void GraphicsSystem::clearObject(int obj_number) {
 
780
  graphics_object_impl_->foreground_objects.deleteAt(obj_number);
 
781
  graphics_object_impl_->background_objects.deleteAt(obj_number);
 
782
}
 
783
 
 
784
// -----------------------------------------------------------------------
 
785
 
580
786
void GraphicsSystem::clearAllObjects() {
581
787
  graphics_object_impl_->foreground_objects.clear();
582
788
  graphics_object_impl_->background_objects.clear();
655
861
// -----------------------------------------------------------------------
656
862
 
657
863
void GraphicsSystem::renderObjects(std::ostream* tree) {
658
 
  // Render all visible foreground objects
 
864
  // The tuple is order, layer, depth, objid, GraphicsObject. Tuples are easy
 
865
  // to sort.
 
866
  typedef std::vector<boost::tuple<int, int, int, int, GraphicsObject*> >
 
867
      ToRenderVec;
 
868
  ToRenderVec to_render;
 
869
 
 
870
  // Collate all objects that we might want to render.
659
871
  AllocatedLazyArrayIterator<GraphicsObject> it =
660
872
    graphics_object_impl_->foreground_objects.allocated_begin();
661
873
  AllocatedLazyArrayIterator<GraphicsObject> end =
671
883
    else if (settings.space_key && interfaceHidden())
672
884
      continue;
673
885
 
674
 
    it->render(it.pos(), tree);
 
886
    to_render.push_back(boost::make_tuple(
 
887
        it->zOrder(), it->zLayer(), it->zDepth(), it.pos(), &*it));
 
888
  }
 
889
 
 
890
  // Sort by all the ordering values.
 
891
  std::sort(to_render.begin(), to_render.end());
 
892
 
 
893
  for (ToRenderVec::iterator it = to_render.begin(); it != to_render.end();
 
894
       ++it) {
 
895
    it->get<4>()->render(it->get<3>(), NULL, tree);
675
896
  }
676
897
}
677
898
 
686
907
    if (it != cursor_cache_.end()) {
687
908
      mouse_cursor_ = it->second;
688
909
    } else {
689
 
      boost::shared_ptr<Surface> cursor_surface;
690
 
      GameexeInterpretObject cursor_key =
691
 
        system().gameexe()("MOUSE_CURSOR", cursor_, "NAME");
692
 
 
693
 
      if (cursor_key.exists()) {
694
 
        cursor_surface = loadNonCGSurfaceFromFile(cursor_key);
695
 
        mouse_cursor_.reset(new MouseCursor(cursor_surface));
 
910
      boost::shared_ptr<const Surface> cursor_surface;
 
911
      GameexeInterpretObject cursor =
 
912
          system().gameexe()("MOUSE_CURSOR", cursor_);
 
913
      GameexeInterpretObject name_key = cursor("NAME");
 
914
 
 
915
      if (name_key.exists()) {
 
916
        int count = cursor("CONT").to_int(1);
 
917
        int speed = cursor("SPEED").to_int(800);
 
918
 
 
919
        cursor_surface = getSurfaceNamed(name_key);
 
920
        mouse_cursor_.reset(
 
921
            new MouseCursor(system(), cursor_surface, count, speed));
696
922
        cursor_cache_[cursor_] = mouse_cursor_;
697
923
      } else {
698
924
        mouse_cursor_.reset();