2 #include <snes/snes.hpp>
11 typedef uint8_t uint8
;
12 typedef uint16_t uint16
;
13 typedef uint32_t uint32
;
15 typedef int16_t int16
;
16 typedef int32_t int32
;
17 #include <nall/platform.hpp>
18 #include <nall/endian.hpp>
19 #include <nall/varint.hpp>
20 #include <nall/bit.hpp>
21 #include <nall/serializer.hpp>
22 #include <nall/property.hpp>
24 #include <ui-libsnes/libsnes.hpp>
28 extern uint32_t fontdata
[];
32 //This is Jenkin's MIX function.
33 uint32_t keyhash(uint32_t key
, uint32_t item
, uint32_t mod
) throw()
38 a
=a
-b
; a
=a
-c
; a
=a
^(c
>> 13);
39 b
=b
-c
; b
=b
-a
; b
=b
^(a
<< 8);
40 c
=c
-a
; c
=c
-b
; c
=c
^(b
>> 13);
41 a
=a
-b
; a
=a
-c
; a
=a
^(c
>> 12);
42 b
=b
-c
; b
=b
-a
; b
=b
^(a
<< 16);
43 c
=c
-a
; c
=c
-b
; c
=c
^(b
>> 5);
44 a
=a
-b
; a
=a
-c
; a
=a
^(c
>> 3);
45 b
=b
-c
; b
=b
-a
; b
=b
^(a
<< 10);
46 c
=c
-a
; c
=c
-b
; c
=c
^(b
>> 15);
51 //Locate glyph in font. Returns <width, offset> pair. Zero offset should be interpretted as an empty
53 std::pair
<uint32_t, size_t> find_glyph(uint32_t codepoint
, int32_t x
, int32_t y
, int32_t orig_x
,
54 int32_t& next_x
, int32_t& next_y
) throw()
58 cwidth
= 64 - (x
- orig_x
) % 64;
61 return std::make_pair(cwidth
, 0);
62 } else if(codepoint
== 10) {
65 return std::make_pair(0, 0);
66 } else if(codepoint
== 32) {
69 return std::make_pair(8, 0);
71 uint32_t mdir
= fontdata
[0];
72 uint32_t mseed
= fontdata
[mdir
];
73 uint32_t msize
= fontdata
[mdir
+ 1];
74 uint32_t midx
= keyhash(mseed
, codepoint
, msize
);
75 uint32_t sdir
= fontdata
[mdir
+ 2 + midx
];
76 if(!fontdata
[sdir
+ 1]) {
77 //Character not found.
80 return std::make_pair(8, 0);
82 uint32_t sseed
= fontdata
[sdir
];
83 uint32_t ssize
= fontdata
[sdir
+ 1];
84 uint32_t sidx
= keyhash(sseed
, codepoint
, ssize
);
85 if(fontdata
[sdir
+ 2 + 2 * sidx
] != codepoint
) {
86 //Character not found.
89 return std::make_pair(8, 0);
91 bool wide
= (fontdata
[fontdata
[sdir
+ 2 + 2 * sidx
+ 1]] != 0);
92 next_x
= x
+ (wide
? 16 : 8);
94 return std::make_pair(wide
? 16 : 8, fontdata
[sdir
+ 2 + 2 * sidx
+ 1] + 1);
98 render_object::~render_object() throw()
102 void render_text(struct screen
& scr
, int32_t x
, int32_t y
, const std::string
& text
, premultiplied_color fg
,
103 premultiplied_color bg
) throw(std::bad_alloc
)
106 uint32_t unicode_code
= 0;
107 uint8_t unicode_left
= 0;
108 for(size_t i
= 0; i
< text
.length(); i
++) {
109 uint8_t ch
= text
[i
];
111 unicode_code
= text
[i
];
115 unicode_code
= 64 * unicode_code
+ ch
- 128;
118 } else if(ch
< 224) {
119 unicode_code
= ch
- 192;
122 } else if(ch
< 240) {
123 unicode_code
= ch
- 224;
126 } else if(ch
< 248) {
127 unicode_code
= ch
- 240;
132 int32_t next_x
, next_y
;
133 auto p
= find_glyph(unicode_code
, x
, y
, orig_x
, next_x
, next_y
);
135 uint32_t dw
= p
.first
;
138 uint32_t cx
= static_cast<uint32_t>(static_cast<int32_t>(scr
.originx
) + x
);
139 uint32_t cy
= static_cast<uint32_t>(static_cast<int32_t>(scr
.originy
) + y
);
140 while(cx
> scr
.width
&& dw
> 0) {
145 while(cy
> scr
.height
&& dh
> 0) {
150 while(cx
+ dw
> scr
.width
&& dw
> 0)
152 while(cy
+ dh
> scr
.height
&& dh
> 0)
155 continue; //Outside screen.
159 for(uint32_t j
= 0; j
< dh
; j
++) {
160 uint32_t* base
= scr
.rowptr(cy
+ j
) + cx
;
161 for(uint32_t i
= 0; i
< dw
; i
++)
166 for(uint32_t j
= 0; j
< dh
; j
++) {
167 uint32_t dataword
= fontdata
[p
.second
+ (dy
+ j
) / (32 / p
.first
)];
168 uint32_t* base
= scr
.rowptr(cy
+ j
) + cx
;
169 for(uint32_t i
= 0; i
< dw
; i
++)
170 if(((dataword
>> (31 - ((dy
+ j
) % (32 / p
.first
)) * p
.first
- (dx
+ i
))) & 1))
181 void render_queue::add(struct render_object
& obj
) throw(std::bad_alloc
)
186 void render_queue::run(struct screen
& scr
) throw()
198 void render_queue::clear() throw()
205 render_queue::~render_queue() throw()
210 uint32_t screen::make_color(uint8_t r
, uint8_t g
, uint8_t b
) throw()
215 return (_r
<< 16) + (_g
<< 8) + _b
;
218 lcscreen::lcscreen(const uint32_t* mem
, bool hires
, bool interlace
, bool overscan
, bool region
) throw()
220 uint32_t dataoffset
= 0;
221 width
= hires
? 512 : 256;
226 dataoffset
= overscan
? 9 : 1;
230 dataoffset
= overscan
? 16 : 9;
234 memory
= mem
+ dataoffset
* 1024;
235 pitch
= interlace
? 512 : 1024;
239 lcscreen::lcscreen(const uint32_t* mem
, uint32_t _width
, uint32_t _height
) throw()
248 lcscreen::lcscreen() throw()
258 lcscreen::lcscreen(const lcscreen
& ls
) throw(std::bad_alloc
)
264 allocated
= static_cast<size_t>(width
) * height
;
265 memory
= new uint32_t[allocated
];
266 for(size_t l
= 0; l
< height
; l
++)
267 memcpy(const_cast<uint32_t*>(memory
+ l
* width
), ls
.memory
+ l
* ls
.pitch
, 4 * width
);
270 lcscreen
& lcscreen::operator=(const lcscreen
& ls
) throw(std::bad_alloc
, std::runtime_error
)
273 throw std::runtime_error("Can't copy to non-user memory");
276 if(allocated
< static_cast<size_t>(ls
.width
) * ls
.height
) {
277 size_t p_allocated
= static_cast<size_t>(ls
.width
) * ls
.height
;
278 memory
= new uint32_t[p_allocated
];
279 allocated
= p_allocated
;
284 for(size_t l
= 0; l
< height
; l
++)
285 memcpy(const_cast<uint32_t*>(memory
+ l
* width
), ls
.memory
+ l
* ls
.pitch
, 4 * width
);
289 lcscreen::~lcscreen()
292 delete[] const_cast<uint32_t*>(memory
);
295 void lcscreen::load(const std::vector
<char>& data
) throw(std::bad_alloc
, std::runtime_error
)
298 throw std::runtime_error("Can't load to non-user memory");
299 const uint8_t* data2
= reinterpret_cast<const uint8_t*>(&data
[0]);
301 throw std::runtime_error("Corrupt saved screenshot data");
302 uint32_t _width
= static_cast<uint32_t>(data2
[0]) * 256 + static_cast<uint32_t>(data2
[1]);
303 if(_width
> 1 && data
.size() % (3 * _width
) != 2)
304 throw std::runtime_error("Corrupt saved screenshot data");
305 uint32_t _height
= (data
.size() - 2) / (3 * _width
);
306 if(allocated
< static_cast<size_t>(_width
) * _height
) {
307 size_t p_allocated
= static_cast<size_t>(_width
) * _height
;
308 memory
= new uint32_t[p_allocated
];
309 allocated
= p_allocated
;
311 uint32_t* mem
= const_cast<uint32_t*>(memory
);
315 for(size_t i
= 0; i
< (data
.size() - 2) / 2; i
++)
316 mem
[i
] = static_cast<uint32_t>(data2
[2 + 3 * i
]) * 65536 +
317 static_cast<uint32_t>(data2
[2 + 3 * i
+ 1]) * 256 +
318 static_cast<uint32_t>(data2
[2 + 3 * i
+ 2]);
321 void lcscreen::save(std::vector
<char>& data
) throw(std::bad_alloc
)
323 data
.resize(2 + 3 * static_cast<size_t>(width
) * height
);
324 uint8_t* data2
= reinterpret_cast<uint8_t*>(&data
[0]);
325 data2
[0] = (width
>> 8);
327 for(size_t i
= 0; i
< (data
.size() - 2) / 3; i
++) {
328 data
[2 + 3 * i
] = memory
[(i
/ width
) * pitch
+ (i
% width
)] >> 16;
329 data
[2 + 3 * i
+ 1] = memory
[(i
/ width
) * pitch
+ (i
% width
)] >> 8;
330 data
[2 + 3 * i
+ 2] = memory
[(i
/ width
) * pitch
+ (i
% width
)];
334 void lcscreen::save_png(const std::string
& file
) throw(std::bad_alloc
, std::runtime_error
)
336 uint8_t* buffer
= new uint8_t[3 * static_cast<size_t>(width
) * height
];
337 for(uint32_t j
= 0; j
< height
; j
++)
338 for(uint32_t i
= 0; i
< width
; i
++) {
339 uint32_t word
= memory
[pitch
* j
+ i
];
340 uint32_t l
= (word
>> 15) & 0xF;
341 uint32_t r
= l
* ((word
>> 0) & 0x1F);
342 uint32_t g
= l
* ((word
>> 5) & 0x1F);
343 uint32_t b
= l
* ((word
>> 10) & 0x1F);
344 buffer
[3 * static_cast<size_t>(width
) * j
+ 3 * i
+ 0] = r
* 255 / 465;
345 buffer
[3 * static_cast<size_t>(width
) * j
+ 3 * i
+ 1] = g
* 255 / 465;
346 buffer
[3 * static_cast<size_t>(width
) * j
+ 3 * i
+ 2] = b
* 255 / 465;
349 save_png_data(file
, buffer
, width
, height
);
357 void screen::copy_from(lcscreen
& scr
, uint32_t hscale
, uint32_t vscale
) throw()
359 uint32_t copyable_width
= (width
- originx
) / hscale
;
360 uint32_t copyable_height
= (height
- originy
) / vscale
;
361 copyable_width
= (copyable_width
> scr
.width
) ? scr
.width
: copyable_width
;
362 copyable_height
= (copyable_height
> scr
.height
) ? scr
.height
: copyable_height
;
363 for(uint32_t y
= 0; y
< height
; y
++) {
364 memset(rowptr(y
), 0, 4 * width
);
366 for(uint32_t y
= 0; y
< copyable_height
; y
++) {
367 uint32_t line
= y
* vscale
+ originy
;
368 uint32_t* ptr
= rowptr(line
) + originx
;
369 const uint32_t* sbase
= scr
.memory
+ y
* scr
.pitch
;
370 for(uint32_t x
= 0; x
< copyable_width
; x
++) {
371 uint32_t c
= palette
[sbase
[x
] & 0x7FFFF];
372 for(uint32_t i
= 0; i
< hscale
; i
++)
375 for(uint32_t j
= 1; j
< vscale
; j
++)
376 memcpy(rowptr(line
+ j
) + originx
, rowptr(line
) + originx
, 4 * hscale
* copyable_width
);
380 void screen::reallocate(uint32_t _width
, uint32_t _height
, uint32_t _originx
, uint32_t _originy
, bool upside_down
)
381 throw(std::bad_alloc
)
383 if(_width
== width
&& _height
== height
) {
388 if(!_width
|| !_height
) {
389 width
= height
= originx
= originy
= pitch
= 0;
390 if(memory
&& !user_memory
)
394 flipped
= upside_down
;
397 uint32_t* newmem
= new uint32_t[_width
* _height
];
403 if(memory
&& !user_memory
)
407 flipped
= upside_down
;
410 void screen::set(uint32_t* _memory
, uint32_t _width
, uint32_t _height
, uint32_t _originx
, uint32_t _originy
,
411 uint32_t _pitch
) throw()
413 if(memory
&& !user_memory
)
425 uint32_t* screen::rowptr(uint32_t row
) throw()
428 row
= height
- row
- 1;
429 return reinterpret_cast<uint32_t*>(reinterpret_cast<uint8_t*>(memory
) + row
* pitch
);
432 screen::screen() throw()
435 width
= height
= originx
= originy
= pitch
= 0;
439 set_palette(16, 8, 0);
442 screen::~screen() throw()
444 if(memory
&& !user_memory
)
448 void clip_range(uint32_t origin
, uint32_t size
, int32_t base
, int32_t& minc
, int32_t& maxc
) throw()
450 int64_t _origin
= origin
;
451 int64_t _size
= size
;
452 int64_t _base
= base
;
453 int64_t _minc
= minc
;
454 int64_t _maxc
= maxc
;
455 int64_t mincoordinate
= _base
+ _origin
+ _minc
;
456 int64_t maxcoordinate
= _base
+ _origin
+ _maxc
;
457 if(mincoordinate
< 0)
458 _minc
= _minc
- mincoordinate
;
459 if(maxcoordinate
> _size
)
460 _maxc
= _maxc
- (maxcoordinate
- _size
);
470 void screen::set_palette(uint32_t r
, uint32_t g
, uint32_t b
)
473 palette
= new uint32_t[0x80000];
474 else if(r
== palette_r
&& g
== palette_g
&& b
== palette_b
)
476 for(size_t i
= 0; i
< static_cast<size_t>(width
) * height
; i
++) {
477 uint32_t word
= memory
[i
];
478 uint32_t R
= (word
>> palette_r
) & 0xFF;
479 uint32_t G
= (word
>> palette_g
) & 0xFF;
480 uint32_t B
= (word
>> palette_b
) & 0xFF;
481 memory
[i
] = (R
<< r
) | (G
<< g
) | (B
<< b
);
483 for(unsigned i
= 0; i
< 0x80000; i
++) {
484 unsigned l
= (i
>> 15) & 0xF;
485 unsigned R
= (i
>> 0) & 0x1F;
486 unsigned G
= (i
>> 5) & 0x1F;
487 unsigned B
= (i
>> 10) & 0x1F;
488 double _l
= static_cast<double>(l
);
489 double m
= 17.0 / 31.0;
490 R
= floor(m
* R
* _l
+ 0.5);
491 G
= floor(m
* G
* _l
+ 0.5);
492 B
= floor(m
* B
* _l
+ 0.5);
493 palette
[i
] = (R
<< r
) | (G
<< g
) | (B
<< b
);