1 #include "hardsubs.hpp"
9 #include "timeparse.hpp"
15 std::map
<unsigned char, std::string
> variables
;
19 if(!variables
.count('\\'))
20 variables
['\\'] = '\\';
21 if(!variables
.count('A'))
22 variables
['A'] = "(unknown)";
23 if(!variables
.count('R'))
24 variables
['R'] = "(unknown)";
25 if(!variables
.count('L'))
26 variables
['L'] = "(unknown)";
27 if(!variables
.count('G'))
28 variables
['G'] = "(unknown)";
31 void copy_surface(SDL_Surface
* s
, unsigned char* buffer
, uint32_t total_width
, uint32_t y
,
32 uint32_t align_type
, uint32_t extralines
)
40 xalign
= (total_width
- s
->w
) / 2;
43 xalign
= total_width
- s
->w
;
47 for(uint32_t y2
= 0; y2
< s
->h
+ extralines
; y2
++)
48 for(uint32_t x
= 0; x
< total_width
; x
++) {
49 if(x
< xalign
|| x
> xalign
+ (uint32_t)s
->w
|| y2
>= (uint32_t)s
->h
)
50 buffer
[(y
+ y2
) * total_width
+ x
] = 0;
52 buffer
[(y
+ y2
) * total_width
+ x
] =
53 ((unsigned char*)s
->pixels
)[y2
* s
->pitch
+ (x
- xalign
)];
58 void render_halo(uint32_t w
, uint32_t h
, unsigned char* data
, uint32_t _thickness
)
60 int32_t thickness
= _thickness
;
61 for(uint32_t y
= 0; y
< h
; y
++)
62 for(uint32_t x
= 0; x
< w
; x
++) {
63 bool left
= (x
> 0) ? (data
[y
* w
+ x
- 1] == 1) : false;
64 bool up
= (y
> 0) ? (data
[y
* w
+ x
- w
] == 1) : false;
65 if(data
[y
* w
+ x
] != 1)
68 for(int32_t j
= up
? thickness
: -thickness
; j
<= thickness
; j
++) {
69 if(y
+ j
< 0 || y
+ j
>= h
)
71 for(int32_t i
= left
? thickness
: -thickness
; i
<= thickness
; i
++) {
72 if(x
+ i
< 0 || x
+ i
>= w
)
74 if(data
[(y
+ j
) * w
+ (x
+ i
)] == 0)
75 data
[(y
+ j
) * w
+ (x
+ i
)] = 2;
82 image_frame_rgbx
* hardsub_render_settings::operator()()
84 std::list
<SDL_Surface
*> lines
;
86 throw std::runtime_error("No font set");
89 if(!TTF_WasInit() && TTF_Init() < 0) {
90 std::stringstream str
;
91 str
<< "Can't initialize SDL_ttf: " << TTF_GetError();
92 throw std::runtime_error(str
.str());
95 //Open the font and render the text.
96 TTF_Font
* font
= TTF_OpenFont(font_name
.c_str(), font_size
);
99 clr
.r
= clr
.g
= clr
.b
= 255;
100 std::string tmp
= "";
102 for(size_t i
= 0; i
< text
.length(); i
++) {
103 char tmp2
[2] = {0, 0};
111 else if(variables
.count(text
[i
])) {
112 tmp
+= variables
[text
[i
]];
114 } else if(text
[i
] == 'n') {
115 SDL_Surface
* s
= TTF_RenderUTF8_Solid(font
, tmp
.c_str(), clr
);
117 throw std::runtime_error("Can't render text");
122 std::stringstream str
;
123 str
<< "Bad escape character '" << text
[i
] << "'";
124 throw std::runtime_error(str
.str());
128 SDL_Surface
* s
= TTF_RenderUTF8_Solid(font
, tmp
.c_str(), clr
);
130 throw std::runtime_error("Can't render text");
139 //Calculate image size and allocate buffers.
140 uint32_t total_width
= 0;
141 uint32_t total_height
= 0;
142 unsigned char* buffer1
= NULL
;
143 image_frame_rgbx
* img
= NULL
;
144 for(std::list
<SDL_Surface
*>::iterator i
= lines
.begin(); i
!= lines
.end(); ++i
) {
145 if((*i
)->w
+ 2 * halo_thickness
> total_width
)
146 total_width
= (*i
)->w
+ 2 * halo_thickness
;
147 total_height
+= ((*i
)->h
+ 2 * halo_thickness
+ spacing
);
150 buffer1
= new unsigned char[total_width
* total_height
];
151 img
= new image_frame_rgbx(total_width
, total_height
);
159 //Copy SDL surfaces to index buffer.
161 for(std::list
<SDL_Surface
*>::iterator i
= lines
.begin(); i
!= lines
.end(); ++i
) {
162 copy_surface(*i
, buffer1
, total_width
, line
, align_type
, spacing
+ 2 * halo_thickness
);
163 line
+= ((*i
)->h
+ spacing
+ 2 * halo_thickness
);
166 render_halo(total_width
, total_height
, buffer1
, halo_thickness
);
168 //Make full color buffer from indexed buffer.
169 uint v0
= 0, v1
= 0, v2
= 0;
170 unsigned char* data
= img
->get_pixels();
171 for(uint32_t y
= 0; y
< total_height
; y
++)
172 for(uint32_t x
= 0; x
< total_width
; x
++)
173 switch(buffer1
[y
* total_width
+ x
]) {
176 data
[y
* 4 * total_width
+ 4 * x
+ 0] = background_r
;
177 data
[y
* 4 * total_width
+ 4 * x
+ 1] = background_g
;
178 data
[y
* 4 * total_width
+ 4 * x
+ 2] = background_b
;
179 data
[y
* 4 * total_width
+ 4 * x
+ 3] = background_a
;
183 data
[y
* 4 * total_width
+ 4 * x
+ 0] = foreground_r
;
184 data
[y
* 4 * total_width
+ 4 * x
+ 1] = foreground_g
;
185 data
[y
* 4 * total_width
+ 4 * x
+ 2] = foreground_b
;
186 data
[y
* 4 * total_width
+ 4 * x
+ 3] = foreground_a
;
190 data
[y
* 4 * total_width
+ 4 * x
+ 0] = halo_r
;
191 data
[y
* 4 * total_width
+ 4 * x
+ 1] = halo_g
;
192 data
[y
* 4 * total_width
+ 4 * x
+ 2] = halo_b
;
193 data
[y
* 4 * total_width
+ 4 * x
+ 3] = halo_a
;
200 void hardsub_settings::reset()
202 rsettings
.font_size
= DEFAULT_FONT_SIZE
;
203 rsettings
.halo_thickness
= DEFAULT_HALO_THICKNESS
;
204 rsettings
.foreground_r
= DEFAULT_FOREGROUND_R
;
205 rsettings
.foreground_g
= DEFAULT_FOREGROUND_G
;
206 rsettings
.foreground_b
= DEFAULT_FOREGROUND_B
;
207 rsettings
.foreground_a
= DEFAULT_FOREGROUND_A
;
208 rsettings
.halo_r
= DEFAULT_HALO_R
;
209 rsettings
.halo_g
= DEFAULT_HALO_G
;
210 rsettings
.halo_b
= DEFAULT_HALO_B
;
211 rsettings
.halo_a
= DEFAULT_HALO_A
;
212 rsettings
.background_r
= DEFAULT_BACKGROUND_R
;
213 rsettings
.background_g
= DEFAULT_BACKGROUND_G
;
214 rsettings
.background_b
= DEFAULT_BACKGROUND_B
;
215 rsettings
.background_a
= DEFAULT_BACKGROUND_A
;
216 rsettings
.align_type
= DEFAULT_ALIGN_TYPE
;
217 rsettings
.spacing
= DEFAULT_SPACING
;
218 duration
= DEFAULT_DURATION
;
219 xalign_type
= DEFAULT_XALIGN_TYPE
;
220 yalign_type
= DEFAULT_YALIGN_TYPE
;
224 hardsub_settings::hardsub_settings()
229 subtitle
* hardsub_settings::operator()()
232 image_frame_rgbx
* img
= rsettings();
234 subtitle
* sub
= new subtitle();
235 sub
->timecode
= timecode
;
236 sub
->duration
= duration
;
237 sub
->xalign_type
= xalign_type
;
238 sub
->xalign
= xalign
;
239 sub
->yalign_type
= yalign_type
;
240 sub
->yalign
= yalign
;
241 sub
->used_settings
= rsettings
;
242 sub
->subtitle_img
= img
;
250 void render_subtitle(image_frame_rgbx
& bottom
, struct subtitle
& sub
)
252 int32_t xalign
, yalign
;
255 switch(sub
.xalign_type
) {
260 xalign
= ((int32_t)bottom
.get_width() - (int32_t)sub
.subtitle_img
->get_width()) / 2;
263 xalign
= (int32_t)bottom
.get_width() - (int32_t)sub
.subtitle_img
->get_width();
270 switch(sub
.yalign_type
) {
275 yalign
= ((int32_t)bottom
.get_height() - (int32_t)sub
.subtitle_img
->get_height()) / 2;
278 yalign
= (int32_t)bottom
.get_height() - (int32_t)sub
.subtitle_img
->get_height();
284 if(xalign
< -(int32_t)sub
.subtitle_img
->get_width() || yalign
< -(int32_t)sub
.subtitle_img
->get_height())
285 return; //Outside image.
286 if(xalign
>= (int32_t)bottom
.get_width() || yalign
>= (int32_t)bottom
.get_height())
287 return; //Outside image.
288 if(sub
.subtitle_img
->get_width() == 0 || sub
.subtitle_img
->get_height() == 0)
289 return; //Nothing to draw.
291 uint32_t overlay_xoffset
= (xalign
< 0) ? -xalign
: 0;
292 uint32_t overlay_yoffset
= (yalign
< 0) ? -yalign
: 0;
293 uint32_t overlay_width
= sub
.subtitle_img
->get_width() - overlay_xoffset
;
294 uint32_t overlay_height
= sub
.subtitle_img
->get_height() - overlay_yoffset
;
299 if(xalign
+ overlay_width
> bottom
.get_width())
300 overlay_width
= bottom
.get_width() - xalign
;
301 if(yalign
+ overlay_height
> bottom
.get_height())
302 overlay_height
= bottom
.get_height() - yalign
;
304 for(uint32_t y
= 0; y
< overlay_height
; y
++) {
305 unsigned char* bottomr
= bottom
.get_pixels() + ((y
+ yalign
) * 4 * bottom
.get_width()) + 4 * xalign
;
306 unsigned char* overlayr
= sub
.subtitle_img
->get_pixels() + ((y
+ overlay_yoffset
) * 4 *
307 sub
.subtitle_img
->get_width()) + 4 * overlay_xoffset
;
308 for(uint32_t x
= 0; x
< overlay_width
; x
++) {
309 uint32_t ibase
= x
* 4;
310 int alpha
= overlayr
[ibase
+ 3];
311 bottomr
[ibase
+ 0] = (unsigned char)((overlayr
[ibase
+ 0] * alpha
+ bottomr
[ibase
+ 0] *
312 (255 - alpha
)) / 255);
313 bottomr
[ibase
+ 1] = (unsigned char)((overlayr
[ibase
+ 1] * alpha
+ bottomr
[ibase
+ 1] *
314 (255 - alpha
)) / 255);
315 bottomr
[ibase
+ 2] = (unsigned char)((overlayr
[ibase
+ 2] * alpha
+ bottomr
[ibase
+ 2] *
316 (255 - alpha
)) / 255);
317 bottomr
[ibase
+ 3] = 0;
322 std::list
<hardsub_settings
*> settings_stack
;
326 int64_t signed_settingvalue(const std::string
& _setting
, int64_t limit_low
, int64_t limit_high
)
328 std::string setting
= settingvalue(_setting
);
330 uint64_t rawparsed
= 0;
331 bool negative
= false;
333 if(setting
.length() > 0 && setting
[0] == '-') {
337 if(index
== setting
.length())
338 throw std::runtime_error("Bad number");
340 for(; index
< setting
.length(); index
++) {
341 if(setting
[index
] < '0' || setting
[index
] > '9')
342 throw std::runtime_error("Bad number");
343 if(rawparsed
>= 0xFFFFFFFFFFFFFFFFULL
/ 10)
344 throw std::runtime_error("Number absolute value too large");
345 rawparsed
= 10 * rawparsed
+ (setting
[index
] - '0');
348 //Take negation if needed and check range.
350 if(rawparsed
> 0x7FFFFFFFFFFFFFFFULL
)
351 throw std::runtime_error("Value overflows");
355 if(rawparsed
> 0x8000000000000000ULL
)
356 throw std::runtime_error("Value underflows");
357 else if(rawparsed
== 0x8000000000000000ULL
)
358 parsed
= 2 * -(int64_t)(1ULL << 62);
360 parsed
= -(int64_t)rawparsed
;
362 if(parsed
< limit_low
|| parsed
> limit_high
)
363 throw std::runtime_error("Value outside valid range");
367 uint64_t time_settingvalue(const std::string
& setting
)
369 std::string v
= settingvalue(setting
);
370 return parse_timespec(v
);
373 void color_settingvalue(const std::string
& setting
, uint8_t& r
, uint8_t& g
, uint8_t& b
, uint8_t& a
)
375 std::string v
= settingvalue(setting
);
377 size_t component
= 0;
379 while(index
< v
.length()) {
381 throw std::runtime_error("Bad color specification");
383 //Find the start of next component and component length.
384 size_t tmp
= v
.find_first_of(",", index
);
385 size_t cstart
= index
;
387 if(tmp
> v
.length()) {
389 clength
= v
.length() - cstart
;
392 clength
= tmp
- cstart
;
396 if(clength
== 0 || clength
> 3)
397 throw std::runtime_error("Bad color specification");
398 for(size_t i
= 0; i
< clength
; i
++)
399 if(v
[cstart
+ i
] < '0' || v
[cstart
+ i
] > '9')
400 throw std::runtime_error("Bad color specification");
402 value
= value
* 10 + (v
[cstart
+ i
] - '0');
404 throw std::runtime_error("Bad color specification");
405 c
[component
] = value
;
410 throw std::runtime_error("Bad color specification");
411 else if(component
== 1) {
413 } else if(component
== 2) {
416 } else if(component
== 3) {
420 } else if(component
== 4) {
428 subtitle
* parse_subtitle_option_one(struct hardsub_settings
& settings
, const std::string
& option
)
430 if(isstringprefix(option
, "font="))
431 settings
.rsettings
.font_name
= settingvalue(option
);
432 else if(isstringprefix(option
, "size="))
433 settings
.rsettings
.font_size
= signed_settingvalue(option
, 1, 10000);
434 else if(isstringprefix(option
, "spacing="))
435 settings
.rsettings
.spacing
= signed_settingvalue(option
, 0, 10000);
436 else if(isstringprefix(option
, "duration="))
437 settings
.duration
= time_settingvalue(option
);
438 else if(option
== "xpos=left")
439 settings
.xalign_type
= ALIGN_LEFT
;
440 else if(option
== "xpos=center")
441 settings
.xalign_type
= ALIGN_CENTER
;
442 else if(option
== "xpos=right")
443 settings
.xalign_type
= ALIGN_RIGHT
;
444 else if(isstringprefix(option
, "xpos=")) {
445 settings
.xalign
= signed_settingvalue(option
, -2000000000, 2000000000);
446 settings
.xalign_type
= ALIGN_CUSTOM
;
447 } else if(option
== "ypos=top")
448 settings
.yalign_type
= ALIGN_TOP
;
449 else if(option
== "ypos=center")
450 settings
.yalign_type
= ALIGN_CENTER
;
451 else if(option
== "ypos=bottom")
452 settings
.yalign_type
= ALIGN_BOTTOM
;
453 else if(isstringprefix(option
, "ypos=")) {
454 settings
.yalign
= signed_settingvalue(option
, -2000000000, 2000000000);
455 settings
.yalign_type
= ALIGN_CUSTOM
;
456 } else if(isstringprefix(option
, "halo="))
457 settings
.rsettings
.halo_thickness
= signed_settingvalue(option
, 0, 1000);
458 else if(option
== "textalign=left")
459 settings
.rsettings
.align_type
= ALIGN_LEFT
;
460 else if(option
== "textalign=center")
461 settings
.rsettings
.align_type
= ALIGN_CENTER
;
462 else if(option
== "textalign=right")
463 settings
.rsettings
.align_type
= ALIGN_RIGHT
;
464 else if(option
== "reset")
466 else if(option
== "push")
467 settings_stack
.push_back(new hardsub_settings(settings
));
468 else if(option
== "pop") {
469 if(settings_stack
.empty())
470 throw std::runtime_error("Attempt to pop empty stack");
471 hardsub_settings
* s
= settings_stack
.back();
472 settings_stack
.pop_back();
475 } else if(isstringprefix(option
, "text=")) {
476 std::string tmp
= settingvalue(option
);
477 size_t split
= tmp
.find_first_of(",");
478 if(split
> tmp
.length())
479 throw std::runtime_error("Bad text syntax");
480 settings
.timecode
= parse_timespec(tmp
.substr(0, split
));
481 settings
.rsettings
.text
= tmp
.substr(split
+ 1);
483 } else if(isstringprefix(option
, "foreground-color=")) {
484 uint8_t r
= 255, g
= 255, b
= 255, a
= 255;
485 color_settingvalue(option
, r
, g
, b
, a
);
486 settings
.rsettings
.foreground_r
= r
;
487 settings
.rsettings
.foreground_g
= g
;
488 settings
.rsettings
.foreground_b
= b
;
489 settings
.rsettings
.foreground_a
= a
;
490 } else if(isstringprefix(option
, "halo-color=")) {
491 uint8_t r
= 0, g
= 0, b
= 0, a
= 255;
492 color_settingvalue(option
, r
, g
, b
, a
);
493 settings
.rsettings
.halo_r
= r
;
494 settings
.rsettings
.halo_g
= g
;
495 settings
.rsettings
.halo_b
= b
;
496 settings
.rsettings
.halo_a
= a
;
497 } else if(isstringprefix(option
, "background-color=")) {
498 uint8_t r
= 0, g
= 0, b
= 0, a
= 0;
499 color_settingvalue(option
, r
, g
, b
, a
);
500 settings
.rsettings
.background_r
= r
;
501 settings
.rsettings
.background_g
= g
;
502 settings
.rsettings
.background_b
= b
;
503 settings
.rsettings
.background_a
= a
;
505 throw std::runtime_error("Unknown subtitle option");
511 std::list
<subtitle
*> parse_subtitle_option(struct hardsub_settings
& settings
, const std::string
& option
)
513 std::list
<subtitle
*> list
;
515 if(isstringprefix(option
, "script=")) {
516 std::string filename
= settingvalue(option
);
517 std::ifstream
stream(filename
.c_str());
519 throw std::runtime_error("Can't open script file");
522 std::getline(stream
, opt
);
525 subtitle
* x
= parse_subtitle_option_one(settings
, opt
);
529 if(!stream
.eof() && (stream
.bad() || stream
.fail()))
530 throw std::runtime_error("Can't read script file");
532 subtitle
* x
= parse_subtitle_option_one(settings
, option
);
540 void print_hardsubs_help(const std::string
& prefix
)
542 std::cout
<< prefix
<< "font=<file>" << std::endl
;
543 std::cout
<< "\tUse the specified font." << std::endl
;
544 std::cout
<< prefix
<< "size=<size>" << std::endl
;
545 std::cout
<< "\tUse the specified font size (default 16)." << std::endl
;
546 std::cout
<< prefix
<< "xpos=<pixels>" << std::endl
;
547 std::cout
<< "\tUse the specified subtitle x-offset." << std::endl
;
548 std::cout
<< prefix
<< "xpos=left" << std::endl
;
549 std::cout
<< "\tPlace subtitles to left." << std::endl
;
550 std::cout
<< prefix
<< "xpos=center" << std::endl
;
551 std::cout
<< "\tPlace subtitles to center (default)." << std::endl
;
552 std::cout
<< prefix
<< "xpos=right" << std::endl
;
553 std::cout
<< "\tPlace subtitles to right." << std::endl
;
554 std::cout
<< prefix
<< "ypos=<pixels>" << std::endl
;
555 std::cout
<< "\tUse the specified subtitle y-offset." << std::endl
;
556 std::cout
<< prefix
<< "ypos=top" << std::endl
;
557 std::cout
<< "\tPlace subtitles to top." << std::endl
;
558 std::cout
<< prefix
<< "ypos=center" << std::endl
;
559 std::cout
<< "\tPlace subtitles to center." << std::endl
;
560 std::cout
<< prefix
<< "ypos=bottom" << std::endl
;
561 std::cout
<< "\tPlace subtitles to bottom (default)." << std::endl
;
562 std::cout
<< prefix
<< "duration=<duration>" << std::endl
;
563 std::cout
<< "\tSubtitles last <duration>." << std::endl
;
564 std::cout
<< prefix
<< "halo=<thickness>" << std::endl
;
565 std::cout
<< "\tSubtitle halo thickness <thickness>." << std::endl
;
566 std::cout
<< prefix
<< "foreground-color=<a>" << std::endl
;
567 std::cout
<< prefix
<< "foreground-color=<rgb>,<a>" << std::endl
;
568 std::cout
<< prefix
<< "foreground-color=<r>,<g>,<b>" << std::endl
;
569 std::cout
<< prefix
<< "foreground-color=<r>,<g>,<b>,<a>" << std::endl
;
570 std::cout
<< "\tSet foreground color. Default is fully opaque white." << std::endl
;
571 std::cout
<< prefix
<< "halo-color=<a>" << std::endl
;
572 std::cout
<< prefix
<< "halo-color=<rgb>,<a>" << std::endl
;
573 std::cout
<< prefix
<< "halo-color=<r>,<g>,<b>" << std::endl
;
574 std::cout
<< prefix
<< "halo-color=<r>,<g>,<b>,<a>" << std::endl
;
575 std::cout
<< "\tSet halo color. Default is fully opaque black." << std::endl
;
576 std::cout
<< prefix
<< "background-color=<a>" << std::endl
;
577 std::cout
<< prefix
<< "background-color=<rgb>,<a>" << std::endl
;
578 std::cout
<< prefix
<< "background-color=<r>,<g>,<b>" << std::endl
;
579 std::cout
<< prefix
<< "background-color=<r>,<g>,<b>,<a>" << std::endl
;
580 std::cout
<< "\tSet background color. Default is fully transparent black." << std::endl
;
581 std::cout
<< prefix
<< "textalign=left" << std::endl
;
582 std::cout
<< prefix
<< "textalign=center" << std::endl
;
583 std::cout
<< prefix
<< "textalign=right" << std::endl
;
584 std::cout
<< "\tSet text alignment between lines. Default is center." << std::endl
;
585 std::cout
<< prefix
<< "spacing=<spacing>" << std::endl
;
586 std::cout
<< "\tSet text spacing between lines. Default is 1." << std::endl
;
587 std::cout
<< prefix
<< "text=<timecode>,<text>" << std::endl
;
588 std::cout
<< "\tDisplay <text> at <timecode>. '\\\\' stands for backslash," << std::endl
;
589 std::cout
<< "\t'\\n' stands for newline." << std::endl
;
590 std::cout
<< prefix
<< "reset" << std::endl
;
591 std::cout
<< "\tReset to defaults." << std::endl
;
592 std::cout
<< prefix
<< "push" << std::endl
;
593 std::cout
<< "\tPush current settings to stack." << std::endl
;
594 std::cout
<< prefix
<< "pop" << std::endl
;
595 std::cout
<< "\tPop settings from stack." << std::endl
;
596 std::cout
<< prefix
<< "script=<file>" << std::endl
;
597 std::cout
<< "\tRead subtitle commands from <file> and do them." << std::endl
;
600 std::list
<subtitle
*> process_hardsubs_options(struct hardsub_settings
& settings
, const std::string
& prefix
, int argc
, char** argv
)
602 std::list
<subtitle
*> global
;
603 for(int i
= 1; i
< argc
; i
++) {
604 std::string arg
= argv
[i
];
607 if(!isstringprefix(arg
, prefix
))
610 std::list
<subtitle
*> local_list
;
611 local_list
= parse_subtitle_option(settings
, arg
.substr(prefix
.length()));
612 for(std::list
<subtitle
*>::iterator i
= local_list
.begin(); i
!= local_list
.end(); i
++)
613 global
.push_back(*i
);
614 } catch(std::exception
& e
) {
615 std::stringstream str
;
616 str
<< "Error processing option '" << arg
<< "': " << e
.what();
617 throw std::runtime_error(str
.str());
623 void subtitle_process_gameinfo(std::list
<subtitle
*>& subs
, struct packet
& p
)
625 if(p
.rp_minor
== 'A' || p
.rp_minor
== 'G') {
626 std::stringstream str
;
627 for(size_t i
= 0; i
< p
.rp_payload
.size(); i
++)
628 str
<< p
.rp_payload
[i
];
629 std::string newarg
= str
.str();
630 subtitle_update_parameter(subs
, p
.rp_minor
, newarg
);
631 } else if(p
.rp_minor
== 'R') {
632 std::stringstream str
;
634 if(p
.rp_payload
.size() < 8)
636 v
|= (uint64_t)p
.rp_payload
[0] << 56;
637 v
|= (uint64_t)p
.rp_payload
[1] << 48;
638 v
|= (uint64_t)p
.rp_payload
[2] << 40;
639 v
|= (uint64_t)p
.rp_payload
[3] << 32;
640 v
|= (uint64_t)p
.rp_payload
[4] << 24;
641 v
|= (uint64_t)p
.rp_payload
[5] << 16;
642 v
|= (uint64_t)p
.rp_payload
[6] << 8;
643 v
|= (uint64_t)p
.rp_payload
[7];
645 std::string newarg
= str
.str();
646 subtitle_update_parameter(subs
, p
.rp_minor
, newarg
);
647 } else if(p
.rp_minor
== 'L') {
648 std::stringstream str
;
650 if(p
.rp_payload
.size() < 8)
652 v
|= (uint64_t)p
.rp_payload
[0] << 56;
653 v
|= (uint64_t)p
.rp_payload
[1] << 48;
654 v
|= (uint64_t)p
.rp_payload
[2] << 40;
655 v
|= (uint64_t)p
.rp_payload
[3] << 32;
656 v
|= (uint64_t)p
.rp_payload
[4] << 24;
657 v
|= (uint64_t)p
.rp_payload
[5] << 16;
658 v
|= (uint64_t)p
.rp_payload
[6] << 8;
659 v
|= (uint64_t)p
.rp_payload
[7];
660 v
= (v
+ 999999) / 1000000;
661 uint64_t hours
= v
/ 3600000;
663 uint64_t minutes
= v
/ 60000;
665 uint64_t seconds
= v
/ 1000;
669 str
<< std::setfill('0') << std::setw(2) << minutes
<< ":" << std::setfill('0')
670 << std::setw(2) << seconds
<< "." << std::setfill('0') << std::setw(3) << v
;
671 std::string newarg
= str
.str();
672 subtitle_update_parameter(subs
, p
.rp_minor
, newarg
);
674 std::cerr
<< "WARNING: Unknown gameinfo type " << (unsigned)p
.rp_minor
<< "." << std::endl
;
678 subtitle::~subtitle()
682 void subtitle_update_parameter(std::list
<subtitle
*>& subs
, unsigned char parameter
, const std::string
& value
)
684 variables
[parameter
] = value
;
685 for(std::list
<subtitle
*>::iterator i
= subs
.begin(); i
!= subs
.end(); ++i
)
687 image_frame_rgbx
* subtitle_img
= (*i
)->subtitle_img
;
688 (*i
)->subtitle_img
= (*i
)->used_settings();
690 } catch(std::exception
& e
) {
699 int main(int argc
, char** argv
)
701 std::list
<subtitle
*> list
, list2
;
703 for(int i
= 1; i
< argc
; i
++) {
704 list2
= parse_subtitle_option(s
, argv
[i
]);
705 for(std::list
<subtitle
*>::iterator j
= list2
.begin(); j
!= list2
.end(); ++j
)
709 SDL_Init(SDL_INIT_EVERYTHING
);
710 for(std::list
<subtitle
*>::iterator i
= list
.begin(); i
!= list
.end(); ++i
) {
711 image_frame_rgbx
& _i
= *((*i
)->subtitle_img
);
712 uint32_t iwidth
= _i
.get_width();
713 const unsigned char* idata
= _i
.get_pixels();
714 SDL_Surface
* s
= SDL_SetVideoMode(_i
.get_width(), _i
.get_height(), 32, SDL_SWSURFACE
| SDL_DOUBLEBUF
);
717 for(uint32_t y
= 0; y
< _i
.get_height(); y
++)
718 for(uint32_t x
= 0; x
< iwidth
; x
++) {
719 ((unsigned char*)s
->pixels
)[y
* s
->pitch
+ 4 * x
+ 0] =
720 idata
[y
* 4 * iwidth
+ 4 * x
+ 0];
721 ((unsigned char*)s
->pixels
)[y
* s
->pitch
+ 4 * x
+ 1] =
722 idata
[y
* 4 * iwidth
+ 4 * x
+ 1];
723 ((unsigned char*)s
->pixels
)[y
* s
->pitch
+ 4 * x
+ 2] =
724 idata
[y
* 4 * iwidth
+ 4 * x
+ 2];
725 ((unsigned char*)s
->pixels
)[y
* s
->pitch
+ 4 * x
+ 3] =
726 idata
[y
* 4 * iwidth
+ 4 * x
+ 3];
728 SDL_UnlockSurface(s
);
733 if(!SDL_WaitEvent(&e
))
734 std::cerr
<< "Can't wait for event" << std::endl
;
735 else if(e
.type
== SDL_QUIT
)