1 #include "cmdhelp/subtitles.hpp"
2 #include "core/command.hpp"
3 #include "core/dispatch.hpp"
4 #include "core/framebuffer.hpp"
5 #include "core/instance.hpp"
6 #include "core/messages.hpp"
7 #include "core/movie.hpp"
8 #include "core/moviefile.hpp"
9 #include "core/subtitles.hpp"
10 #include "fonts/wrapper.hpp"
11 #include "library/string.hpp"
12 #include "lua/lua.hpp"
16 moviefile_subtiming::moviefile_subtiming(uint64_t _frame
)
23 moviefile_subtiming::moviefile_subtiming(uint64_t first
, uint64_t _length
)
25 position_only
= false;
30 bool moviefile_subtiming::operator<(const moviefile_subtiming
& a
) const
32 //This goes in inverse order due to behaviour of lower_bound/upper_bound.
37 if(position_only
&& a
.position_only
)
39 //Position only compares greater than any of same frame.
40 if(position_only
!= a
.position_only
)
42 //Break ties on length.
43 return (length
> a
.length
);
46 bool moviefile_subtiming::operator==(const moviefile_subtiming
& a
) const
50 if(position_only
&& a
.position_only
)
52 if(position_only
!= a
.position_only
)
54 return (length
!= a
.length
);
57 bool moviefile_subtiming::inrange(uint64_t x
) const
61 return (x
>= frame
&& x
< frame
+ length
);
64 uint64_t moviefile_subtiming::get_frame() const { return frame
; }
65 uint64_t moviefile_subtiming::get_length() const { return length
; }
69 std::string
s_subescape(std::string x
)
72 for(size_t i
= 0; i
< x
.length(); i
++) {
84 struct render_object_subtitle
: public framebuffer::object
86 render_object_subtitle(int32_t _x
, int32_t _y
, const std::string
& _text
) throw()
87 : x(_x
), y(_y
), text(_text
), fg(0xFFFF80), bg(-1) {}
88 ~render_object_subtitle() throw() {}
89 template<bool X
> void op(struct framebuffer::fb
<X
>& scr
) throw()
91 main_font
.render(scr
, x
, y
, text
, fg
, bg
, false, false);
93 void operator()(struct framebuffer::fb
<true>& scr
) throw() { op(scr
); }
94 void operator()(struct framebuffer::fb
<false>& scr
) throw() { op(scr
); }
95 void clone(framebuffer::queue
& q
) const { q
.clone_helper(this); }
100 framebuffer::color fg
;
101 framebuffer::color bg
;
105 subtitle_commentary::subtitle_commentary(movie_logic
& _mlogic
, emu_framebuffer
& _fbuf
, emulator_dispatch
& _dispatch
,
106 command::group
& _cmd
)
107 : mlogic(_mlogic
), fbuf(_fbuf
), edispatch(_dispatch
), cmd(_cmd
),
108 editsub(cmd
, CSUBTITLE::edit
, [this](const std::string
& a
) { this->do_editsub(a
); }),
109 listsub(cmd
, CSUBTITLE::list
, [this]() { this->do_listsub(); }),
110 savesub(cmd
, CSUBTITLE::save
, [this](command::arg_filename a
) { this->do_savesub(a
); })
114 std::string
subtitle_commentary::s_escape(std::string x
)
117 for(size_t i
= 0; i
< x
.length(); i
++) {
129 std::string
subtitle_commentary::s_unescape(std::string x
)
133 for(size_t i
= 0; i
< x
.length(); i
++) {
151 void subtitle_commentary::render(lua::render_context
& ctx
)
153 if(!mlogic
|| mlogic
.get_mfile().subtitles
.empty())
155 if(ctx
.bottom_gap
< 32)
157 uint64_t curframe
= mlogic
.get_movie().get_current_frame() + 1;
158 moviefile_subtiming
posmarker(curframe
);
159 auto i
= mlogic
.get_mfile().subtitles
.upper_bound(posmarker
);
160 if(i
!= mlogic
.get_mfile().subtitles
.end() && i
->first
.inrange(curframe
)) {
161 std::string subtxt
= i
->second
;
162 int32_t y
= ctx
.height
;
163 ctx
.queue
->create_add
<render_object_subtitle
>(0, y
, subtxt
);
167 std::set
<std::pair
<uint64_t, uint64_t>> subtitle_commentary::get_all()
169 std::set
<std::pair
<uint64_t, uint64_t>> r
;
172 for(auto i
= mlogic
.get_mfile().subtitles
.rbegin(); i
!=
173 mlogic
.get_mfile().subtitles
.rend(); i
++)
174 r
.insert(std::make_pair(i
->first
.get_frame(), i
->first
.get_length()));
178 std::string
subtitle_commentary::get(uint64_t f
, uint64_t l
)
182 moviefile_subtiming
key(f
, l
);
183 if(!mlogic
.get_mfile().subtitles
.count(key
))
186 return s_escape(mlogic
.get_mfile().subtitles
[key
]);
189 void subtitle_commentary::set(uint64_t f
, uint64_t l
, const std::string
& x
)
193 moviefile_subtiming
key(f
, l
);
195 mlogic
.get_mfile().subtitles
.erase(key
);
197 mlogic
.get_mfile().subtitles
[key
] = s_unescape(x
);
198 edispatch
.subtitle_change();
199 fbuf
.redraw_framebuffer();
202 void subtitle_commentary::do_editsub(const std::string
& args
)
204 auto r
= regex("([0-9]+)[ \t]+([0-9]+)([ \t]+(.*))?", args
, "Bad syntax");
205 uint64_t frame
= parse_value
<uint64_t>(r
[1]);
206 uint64_t length
= parse_value
<uint64_t>(r
[2]);
207 std::string text
= r
[4];
208 moviefile_subtiming
key(frame
, length
);
210 mlogic
.get_mfile().subtitles
.erase(key
);
212 mlogic
.get_mfile().subtitles
[key
] =
213 subtitle_commentary::s_unescape(text
);
214 edispatch
.subtitle_change();
215 fbuf
.redraw_framebuffer();
218 void subtitle_commentary::do_listsub()
220 for(auto i
= mlogic
.get_mfile().subtitles
.rbegin(); i
!=
221 mlogic
.get_mfile().subtitles
.rend();
223 messages
<< i
->first
.get_frame() << " " << i
->first
.get_length() << " "
224 << subtitle_commentary::s_escape(i
->second
) << std::endl
;
228 void subtitle_commentary::do_savesub(const std::string
& args
)
230 if(mlogic
.get_mfile().subtitles
.empty())
232 auto i
= mlogic
.get_mfile().subtitles
.begin();
233 uint64_t lastframe
= i
->first
.get_frame() + i
->first
.get_length();
234 std::ofstream
y(std::string(args
).c_str());
236 throw std::runtime_error("Can't open output file");
237 std::string lasttxt
= "";
239 for(uint64_t i
= 1; i
< lastframe
; i
++) {
240 moviefile_subtiming
posmarker(i
);
241 auto j
= mlogic
.get_mfile().subtitles
.upper_bound(posmarker
);
242 if(j
== mlogic
.get_mfile().subtitles
.end())
244 if(lasttxt
!= j
->second
|| !j
->first
.inrange(i
)) {
246 y
<< "{" << since
<< "}{" << i
- 1 << "}" << s_subescape(lasttxt
)
249 lasttxt
= j
->first
.inrange(i
) ? j
->second
: "";
253 y
<< "{" << since
<< "}{" << lastframe
- 1 << "}" << s_subescape(lasttxt
)
255 messages
<< "Saved subtitles to " << std::string(args
) << std::endl
;