Clean up system font drawing
[lsnes.git] / src / video / raw.cpp
blob67a42ce87254d40ad7f65c3691a1e428114d3a88
1 #include "core/advdumper.hpp"
2 #include "core/dispatch.hpp"
3 #include "core/instance.hpp"
4 #include "core/moviedata.hpp"
5 #include "core/moviefile.hpp"
6 #include "core/messages.hpp"
7 #include "core/rom.hpp"
8 #include "video/tcp.hpp"
9 #include "library/serialization.hpp"
10 #include "library/minmax.hpp"
12 #include <iomanip>
13 #include <cassert>
14 #include <cstring>
15 #include <cerrno>
16 #include <cstring>
17 #include <sstream>
18 #include <fstream>
19 #include <zlib.h>
21 #define IS_RGB(m) (((m) + ((m) >> 3)) & 2)
22 #define IS_64(m) (m % 5 < 2)
23 #define IS_TCP(m) (((m % 5) * (m % 5)) % 5 == 1)
25 namespace
27 unsigned strhash(const std::string& str)
29 unsigned h = 0;
30 for(size_t i = 0; i < str.length(); i++)
31 h = (2 * h + static_cast<unsigned char>(str[i])) % 11;
32 return h;
35 void deleter_fn(void* f)
37 delete reinterpret_cast<std::ofstream*>(f);
40 class raw_dump_obj : public dumper_base
42 public:
43 raw_dump_obj(master_dumper& _mdumper, dumper_factory_base& _fbase, const std::string& mode,
44 const std::string& prefix)
45 : dumper_base(_mdumper, _fbase), mdumper(_mdumper)
47 unsigned _mode = strhash(mode);
48 bool _bits64 = IS_64(_mode);
49 bool _swap = !IS_RGB(_mode);
50 bool socket_mode = IS_TCP(_mode);
52 if(prefix == "")
53 throw std::runtime_error("Expected prefix");
54 try {
55 if(socket_mode) {
56 socket_address videoaddr = socket_address(prefix);
57 socket_address audioaddr = videoaddr.next();
58 deleter = socket_address::deleter();
59 video = audio = NULL;
60 try {
61 video = &videoaddr.connect();
62 audio = &audioaddr.connect();
63 } catch(...) {
64 deleter(video);
65 deleter(audio);
66 throw;
68 } else {
69 video = new std::ofstream(prefix + ".video", std::ios::out |
70 std::ios::binary);
71 audio = new std::ofstream(prefix + ".audio", std::ios::out |
72 std::ios::binary);
73 deleter = deleter_fn;
75 if(!*video || !*audio)
76 throw std::runtime_error("Can't open output files");
77 have_dumped_frame = false;
78 swap = _swap;
79 bits64 = _bits64;
80 mdumper.add_dumper(*this);
81 } catch(std::bad_alloc& e) {
82 throw;
83 } catch(std::exception& e) {
84 std::ostringstream x;
85 x << "Error starting RAW dump: " << e.what();
86 throw std::runtime_error(x.str());
88 messages << "Dumping to " << prefix << std::endl;
90 ~raw_dump_obj() throw()
92 mdumper.drop_dumper(*this);
93 if(video)
94 deleter(video);
95 if(audio)
96 deleter(audio);
97 messages << "RAW Dump finished" << std::endl;
99 void on_frame(struct framebuffer::raw& _frame, uint32_t fps_n, uint32_t fps_d)
101 auto& core = CORE();
102 if(!video)
103 return;
104 uint32_t hscl, vscl;
105 rpair(hscl, vscl) = core.rom->get_scale_factors(_frame.get_width(),
106 _frame.get_height());
107 if(bits64) {
108 size_t w = dscr2.get_width();
109 size_t h = dscr2.get_height();
110 size_t s = dscr2.get_stride();
111 std::vector<uint16_t> tmp;
112 tmp.resize(8 * s + 8);
113 uint32_t alignment = (16 - reinterpret_cast<size_t>(&tmp[0])) % 16 / 2;
114 if(!render_video_hud(dscr2, _frame, fps_n, fps_d, hscl, vscl, 0, 0, 0, 0, NULL))
115 return;
116 for(size_t i = 0; i < h; i++) {
117 if(!swap)
118 framebuffer::copy_swap4(&tmp[alignment], dscr2.rowptr(i), s);
119 else
120 memcpy(&tmp[alignment], dscr2.rowptr(i), 8 * w);
121 video->write(reinterpret_cast<char*>(&tmp[alignment]), 8 * w);
123 } else {
124 size_t w = dscr.get_width();
125 size_t h = dscr.get_height();
126 size_t s = dscr2.get_stride();
127 std::vector<uint8_t> tmp;
128 tmp.resize(4 * s + 16);
129 uint32_t alignment = (16 - reinterpret_cast<size_t>(&tmp[0])) % 16;
130 if(!render_video_hud(dscr, _frame, fps_n, fps_d, hscl, vscl, 0, 0, 0, 0, NULL))
131 return;
132 for(size_t i = 0; i < h; i++) {
133 if(!swap)
134 framebuffer::copy_swap4(&tmp[alignment], dscr.rowptr(i), s);
135 else
136 memcpy(&tmp[alignment], dscr.rowptr(i), 4 * w);
137 video->write(reinterpret_cast<char*>(&tmp[alignment]), 4 * w);
140 if(!*video)
141 messages << "Video write error" << std::endl;
142 have_dumped_frame = true;
145 void on_sample(short l, short r)
147 if(have_dumped_frame && audio) {
148 char buffer[4];
149 serialization::s16b(buffer + 0, l);
150 serialization::s16b(buffer + 2, r);
151 audio->write(buffer, 4);
154 void on_rate_change(uint32_t n, uint32_t d)
156 //Do nothing.
158 void on_gameinfo_change(const master_dumper::gameinfo& gi)
160 //Do nothing.
162 void on_end()
164 delete this;
166 private:
167 std::ostream* audio;
168 std::ostream* video;
169 void (*deleter)(void* f);
170 bool have_dumped_frame;
171 struct framebuffer::fb<false> dscr;
172 struct framebuffer::fb<true> dscr2;
173 bool swap;
174 bool bits64;
175 master_dumper& mdumper;
178 class adv_raw_dumper : public dumper_factory_base
180 public:
181 adv_raw_dumper() : dumper_factory_base("INTERNAL-RAW")
183 ctor_notify();
185 ~adv_raw_dumper() throw();
186 std::set<std::string> list_submodes() throw(std::bad_alloc)
188 std::set<std::string> x;
189 for(size_t i = 0; i < (socket_address::supported() ? 2 : 1); i++)
190 for(size_t j = 0; j < 2; j++)
191 for(size_t k = 0; k < 2; k++)
192 x.insert(std::string("") + (i ? "tcp" : "") + (j ? "bgr" : "rgb")
193 + (k ? "64" : "32"));
194 return x;
196 unsigned mode_details(const std::string& mode) throw()
198 return IS_TCP(strhash(mode)) ? target_type_special : target_type_prefix;
200 std::string mode_extension(const std::string& mode) throw()
202 return ""; //Nothing interesting.
204 std::string name() throw(std::bad_alloc)
206 return "RAW";
208 std::string modename(const std::string& mode) throw(std::bad_alloc)
210 unsigned _mode = strhash(mode);
211 std::string x = std::string((IS_RGB(_mode) ? "RGB" : "BGR")) +
212 (IS_64(_mode) ? " 64-bit" : " 32-bit") + (IS_TCP(_mode) ? " over TCP/IP" : "");
213 return x;
215 raw_dump_obj* start(master_dumper& _mdumper, const std::string& mode, const std::string& prefix)
216 throw(std::bad_alloc, std::runtime_error)
218 return new raw_dump_obj(_mdumper, *this, mode, prefix);
220 } adv;
222 adv_raw_dumper::~adv_raw_dumper() throw()