1 #include "core/command.hpp"
2 #include "core/dispatch.hpp"
3 #include "core/framebuffer.hpp"
4 #include "core/moviedata.hpp"
5 #include "core/subtitles.hpp"
6 #include "core/window.hpp"
7 #include "library/string.hpp"
8 #include "fonts/wrapper.hpp"
11 moviefile_subtiming::moviefile_subtiming(uint64_t _frame
)
18 moviefile_subtiming::moviefile_subtiming(uint64_t first
, uint64_t _length
)
20 position_only
= false;
25 bool moviefile_subtiming::operator<(const moviefile_subtiming
& a
) const
27 //This goes in inverse order due to behaviour of lower_bound/upper_bound.
32 if(position_only
&& a
.position_only
)
34 //Position only compares greater than any of same frame.
35 if(position_only
!= a
.position_only
)
37 //Break ties on length.
38 return (length
> a
.length
);
41 bool moviefile_subtiming::operator==(const moviefile_subtiming
& a
) const
45 if(position_only
&& a
.position_only
)
47 if(position_only
!= a
.position_only
)
49 return (length
!= a
.length
);
52 bool moviefile_subtiming::inrange(uint64_t x
) const
56 return (x
>= frame
&& x
< frame
+ length
);
59 uint64_t moviefile_subtiming::get_frame() const { return frame
; }
60 uint64_t moviefile_subtiming::get_length() const { return length
; }
64 std::string
s_subescape(std::string x
)
67 for(size_t i
= 0; i
< x
.length(); i
++) {
79 struct render_object_subtitle
: public render_object
81 render_object_subtitle(int32_t _x
, int32_t _y
, const std::string
& _text
) throw()
82 : x(_x
), y(_y
), text(_text
), fg(0xFFFF80), bg(-1) {}
83 ~render_object_subtitle() throw() {}
84 template<bool X
> void op(struct framebuffer
<X
>& scr
) throw()
88 main_font
.render(scr
, x
, y
, text
, fg
, bg
, false, false);
90 void operator()(struct framebuffer
<true>& scr
) throw() { op(scr
); }
91 void operator()(struct framebuffer
<false>& scr
) throw() { op(scr
); }
92 void clone(render_queue
& q
) const throw(std::bad_alloc
) { q
.clone_helper(this); }
97 premultiplied_color fg
;
98 premultiplied_color bg
;
102 function_ptr_command
<const std::string
&> edit_subtitle(lsnes_cmd
, "edit-subtitle", "Edit a subtitle",
103 "Syntax: edit-subtitle <first> <length> <text>\nAdd/Edit subtitle\n"
104 "Syntax: edit-subtitle <first> <length>\nADelete subtitle\n",
105 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
106 auto r
= regex("([0-9]+)[ \t]+([0-9]+)([ \t]+(.*))?", args
, "Bad syntax");
107 uint64_t frame
= parse_value
<uint64_t>(r
[1]);
108 uint64_t length
= parse_value
<uint64_t>(r
[2]);
109 std::string text
= r
[4];
110 moviefile_subtiming
key(frame
, length
);
112 our_movie
.subtitles
.erase(key
);
114 our_movie
.subtitles
[key
] = s_unescape(text
);
115 information_dispatch::do_subtitle_change();
116 redraw_framebuffer();
119 function_ptr_command
<> list_subtitle(lsnes_cmd
, "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
= our_movie
.subtitles
.rbegin(); i
!= our_movie
.subtitles
.rend(); i
++) {
123 messages
<< i
->first
.get_frame() << " " << i
->first
.get_length() << " "
124 << s_escape(i
->second
) << std::endl
;
128 function_ptr_command
<arg_filename
> save_s(lsnes_cmd
, "save-subtitle", "Save subtitles in .sub format",
129 "Syntax: save-subtitle <file>\nSaves subtitles in .sub format to <file>\n",
130 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
131 if(our_movie
.subtitles
.empty())
133 auto i
= our_movie
.subtitles
.begin();
134 uint64_t lastframe
= i
->first
.get_frame() + i
->first
.get_length();
135 std::ofstream
y(std::string(args
).c_str());
137 throw std::runtime_error("Can't open output file");
138 std::string lasttxt
= "";
140 for(uint64_t i
= 1; i
< lastframe
; i
++) {
141 moviefile_subtiming
posmarker(i
);
142 auto j
= our_movie
.subtitles
.upper_bound(posmarker
);
143 if(j
== our_movie
.subtitles
.end() || !j
->first
.inrange(i
))
145 if(lasttxt
!= j
->second
) {
147 y
<< "{" << since
<< "}{" << i
- 1 << "}" << s_subescape(lasttxt
)
154 y
<< "{" << since
<< "}{" << lastframe
- 1 << "}" << s_subescape(lasttxt
)
156 messages
<< "Saved subtitles to " << std::string(args
) << std::endl
;
160 std::string
s_escape(std::string x
)
163 for(size_t i
= 0; i
< x
.length(); i
++) {
175 std::string
s_unescape(std::string x
)
179 for(size_t i
= 0; i
< x
.length(); i
++) {
197 void render_subtitles(lua_render_context
& ctx
)
199 if(our_movie
.subtitles
.empty())
201 if(ctx
.bottom_gap
< 32)
203 uint64_t curframe
= movb
.get_movie().get_current_frame() + 1;
204 moviefile_subtiming
posmarker(curframe
);
205 auto i
= our_movie
.subtitles
.upper_bound(posmarker
);
206 if(i
!= our_movie
.subtitles
.end() && i
->first
.inrange(curframe
)) {
207 std::string subtxt
= i
->second
;
208 int32_t y
= ctx
.height
;
209 ctx
.queue
->create_add
<render_object_subtitle
>(0, y
, subtxt
);
213 std::set
<std::pair
<uint64_t, uint64_t>> get_subtitles()
215 std::set
<std::pair
<uint64_t, uint64_t>> r
;
216 for(auto i
= our_movie
.subtitles
.rbegin(); i
!= our_movie
.subtitles
.rend(); i
++)
217 r
.insert(std::make_pair(i
->first
.get_frame(), i
->first
.get_length()));
221 std::string
get_subtitle_for(uint64_t f
, uint64_t l
)
223 moviefile_subtiming
key(f
, l
);
224 if(!our_movie
.subtitles
.count(key
))
227 return s_escape(our_movie
.subtitles
[key
]);
230 void set_subtitle_for(uint64_t f
, uint64_t l
, const std::string
& x
)
232 moviefile_subtiming
key(f
, l
);
234 our_movie
.subtitles
.erase(key
);
236 our_movie
.subtitles
[key
] = s_unescape(x
);
237 information_dispatch::do_subtitle_change();
238 redraw_framebuffer();