1 #include "core/command.hpp"
2 #include "core/dispatch.hpp"
3 #include "core/framebuffer.hpp"
4 #include "core/instance.hpp"
5 #include "core/moviedata.hpp"
6 #include "core/subtitles.hpp"
7 #include "core/window.hpp"
8 #include "library/string.hpp"
9 #include "fonts/wrapper.hpp"
12 moviefile_subtiming::moviefile_subtiming(uint64_t _frame
)
19 moviefile_subtiming::moviefile_subtiming(uint64_t first
, uint64_t _length
)
21 position_only
= false;
26 bool moviefile_subtiming::operator<(const moviefile_subtiming
& a
) const
28 //This goes in inverse order due to behaviour of lower_bound/upper_bound.
33 if(position_only
&& a
.position_only
)
35 //Position only compares greater than any of same frame.
36 if(position_only
!= a
.position_only
)
38 //Break ties on length.
39 return (length
> a
.length
);
42 bool moviefile_subtiming::operator==(const moviefile_subtiming
& a
) const
46 if(position_only
&& a
.position_only
)
48 if(position_only
!= a
.position_only
)
50 return (length
!= a
.length
);
53 bool moviefile_subtiming::inrange(uint64_t x
) const
57 return (x
>= frame
&& x
< frame
+ length
);
60 uint64_t moviefile_subtiming::get_frame() const { return frame
; }
61 uint64_t moviefile_subtiming::get_length() const { return length
; }
65 std::string
s_subescape(std::string x
)
68 for(size_t i
= 0; i
< x
.length(); i
++) {
80 struct render_object_subtitle
: public framebuffer::object
82 render_object_subtitle(int32_t _x
, int32_t _y
, const std::string
& _text
) throw()
83 : x(_x
), y(_y
), text(_text
), fg(0xFFFF80), bg(-1) {}
84 ~render_object_subtitle() throw() {}
85 template<bool X
> void op(struct framebuffer::fb
<X
>& scr
) throw()
87 main_font
.render(scr
, x
, y
, text
, fg
, bg
, false, false);
89 void operator()(struct framebuffer::fb
<true>& scr
) throw() { op(scr
); }
90 void operator()(struct framebuffer::fb
<false>& scr
) throw() { op(scr
); }
91 void clone(framebuffer::queue
& q
) const throw(std::bad_alloc
) { q
.clone_helper(this); }
96 framebuffer::color fg
;
97 framebuffer::color bg
;
101 command::fnptr
<const std::string
&> edit_subtitle(lsnes_cmds
, "edit-subtitle", "Edit a subtitle",
102 "Syntax: edit-subtitle <first> <length> <text>\nAdd/Edit subtitle\n"
103 "Syntax: edit-subtitle <first> <length>\nADelete subtitle\n",
104 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
105 auto r
= regex("([0-9]+)[ \t]+([0-9]+)([ \t]+(.*))?", args
, "Bad syntax");
106 uint64_t frame
= parse_value
<uint64_t>(r
[1]);
107 uint64_t length
= parse_value
<uint64_t>(r
[2]);
108 std::string text
= r
[4];
109 moviefile_subtiming
key(frame
, length
);
111 CORE().mlogic
.get_mfile().subtitles
.erase(key
);
113 CORE().mlogic
.get_mfile().subtitles
[key
] =
114 subtitle_commentary::s_unescape(text
);
115 notify_subtitle_change();
116 CORE().fbuf
.redraw_framebuffer();
119 command::fnptr
<> list_subtitle(lsnes_cmds
, "list-subtitle", "List the subtitles",
120 "Syntax: list-subtitle\nList the subtitles.\n",
121 []() throw(std::bad_alloc
, std::runtime_error
) {
122 for(auto i
= CORE().mlogic
.get_mfile().subtitles
.rbegin(); i
!=
123 CORE().mlogic
.get_mfile().subtitles
.rend();
125 messages
<< i
->first
.get_frame() << " " << i
->first
.get_length() << " "
126 << subtitle_commentary::s_escape(i
->second
) << std::endl
;
130 command::fnptr
<command::arg_filename
> save_s(lsnes_cmds
, "save-subtitle", "Save subtitles in .sub format",
131 "Syntax: save-subtitle <file>\nSaves subtitles in .sub format to <file>\n",
132 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
133 if(CORE().mlogic
.get_mfile().subtitles
.empty())
135 auto i
= CORE().mlogic
.get_mfile().subtitles
.begin();
136 uint64_t lastframe
= i
->first
.get_frame() + i
->first
.get_length();
137 std::ofstream
y(std::string(args
).c_str());
139 throw std::runtime_error("Can't open output file");
140 std::string lasttxt
= "";
142 for(uint64_t i
= 1; i
< lastframe
; i
++) {
143 moviefile_subtiming
posmarker(i
);
144 auto j
= CORE().mlogic
.get_mfile().subtitles
.upper_bound(posmarker
);
145 if(j
== CORE().mlogic
.get_mfile().subtitles
.end())
147 if(lasttxt
!= j
->second
|| !j
->first
.inrange(i
)) {
149 y
<< "{" << since
<< "}{" << i
- 1 << "}" << s_subescape(lasttxt
)
152 lasttxt
= j
->first
.inrange(i
) ? j
->second
: "";
156 y
<< "{" << since
<< "}{" << lastframe
- 1 << "}" << s_subescape(lasttxt
)
158 messages
<< "Saved subtitles to " << std::string(args
) << std::endl
;
162 subtitle_commentary::subtitle_commentary(movie_logic
& _mlogic
, emu_framebuffer
& _fbuf
)
163 : mlogic(_mlogic
), fbuf(_fbuf
)
167 std::string
subtitle_commentary::s_escape(std::string x
)
170 for(size_t i
= 0; i
< x
.length(); i
++) {
182 std::string
subtitle_commentary::s_unescape(std::string x
)
186 for(size_t i
= 0; i
< x
.length(); i
++) {
204 void subtitle_commentary::render(lua::render_context
& ctx
)
206 if(!mlogic
|| mlogic
.get_mfile().subtitles
.empty())
208 if(ctx
.bottom_gap
< 32)
210 uint64_t curframe
= mlogic
.get_movie().get_current_frame() + 1;
211 moviefile_subtiming
posmarker(curframe
);
212 auto i
= mlogic
.get_mfile().subtitles
.upper_bound(posmarker
);
213 if(i
!= mlogic
.get_mfile().subtitles
.end() && i
->first
.inrange(curframe
)) {
214 std::string subtxt
= i
->second
;
215 int32_t y
= ctx
.height
;
216 ctx
.queue
->create_add
<render_object_subtitle
>(0, y
, subtxt
);
220 std::set
<std::pair
<uint64_t, uint64_t>> subtitle_commentary::get_all()
222 std::set
<std::pair
<uint64_t, uint64_t>> r
;
225 for(auto i
= mlogic
.get_mfile().subtitles
.rbegin(); i
!=
226 mlogic
.get_mfile().subtitles
.rend(); i
++)
227 r
.insert(std::make_pair(i
->first
.get_frame(), i
->first
.get_length()));
231 std::string
subtitle_commentary::get(uint64_t f
, uint64_t l
)
235 moviefile_subtiming
key(f
, l
);
236 if(!mlogic
.get_mfile().subtitles
.count(key
))
239 return s_escape(mlogic
.get_mfile().subtitles
[key
]);
242 void subtitle_commentary::set(uint64_t f
, uint64_t l
, const std::string
& x
)
246 moviefile_subtiming
key(f
, l
);
248 mlogic
.get_mfile().subtitles
.erase(key
);
250 mlogic
.get_mfile().subtitles
[key
] = s_unescape(x
);
251 notify_subtitle_change();
252 fbuf
.redraw_framebuffer();