forked from tonioni/WinUAE
-
Notifications
You must be signed in to change notification settings - Fork 1
/
cd32_fmv_genlock.cpp
159 lines (140 loc) · 4.08 KB
/
cd32_fmv_genlock.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
* UAE - The Un*x Amiga Emulator
*
* CD32 FMV video genlock
*
* Copyright 2014 Toni Wilen
*
*/
#include "sysconfig.h"
#include "sysdeps.h"
#include "options.h"
#include "memory.h"
#include "cd32_fmv.h"
#include "xwin.h"
static uae_u8 *mpeg_out_buffer;
static int mpeg_width, mpeg_height, mpeg_depth;
static uae_u32 fmv_border_color;
static uae_u16 fmv_border_color_16;
int cd32_fmv_active;
// According to schematics there is at least 3 (possible more)
// "genlock modes" but they seem to be unused, at least ROM
// mpeg player software never sets any genlock bits.
// this is probably not how it actually works.
#define GENLOCK_VAL_32 0x20
#define GENLOCK_VAL_16 0x03
#define MPEG_PIXBYTES_32 4
#define MPEG_PIXBYTES_16 2
#define MAX_MPEG_WIDTH 352
#define MAX_MPEG_HEIGHT 288
void cd32_fmv_new_border_color(uae_u32 bordercolor)
{
fmv_border_color = bordercolor;
fmv_border_color_16 = (((bordercolor >> (16 + 3)) & 31) << 11);
fmv_border_color_16 |= (((bordercolor >> ( 8 + 2)) & 63) << 5);
fmv_border_color_16 |= (((bordercolor >> ( 0 + 3)) & 31) << 0);
}
void cd32_fmv_new_image(int w, int h, int d, uae_u8 *s)
{
if (!mpeg_out_buffer)
mpeg_out_buffer = xmalloc(uae_u8, MAX_MPEG_WIDTH * MAX_MPEG_HEIGHT * MPEG_PIXBYTES_32);
if (s == NULL || w > MAX_MPEG_WIDTH || h > MAX_MPEG_HEIGHT) {
memset(mpeg_out_buffer, 0, MAX_MPEG_WIDTH * MAX_MPEG_HEIGHT * MPEG_PIXBYTES_32);
mpeg_width = MAX_MPEG_WIDTH;
mpeg_height = MAX_MPEG_HEIGHT;
return;
}
memcpy(mpeg_out_buffer, s, w * h * d);
mpeg_width = w;
mpeg_height = h;
mpeg_depth = d;
}
void cd32_fmv_state(int state)
{
cd32_fmv_active = state;
}
// slow software method but who cares.
static void genlock_32(struct vidbuffer *vbin, struct vidbuffer *vbout, int w, int h, int d, int hoffset, int voffset, int mult)
{
for (int hh = 0, sh = -voffset; hh < h; sh++, hh += mult) {
for (int h2 = 0; h2 < mult; h2++) {
uae_u8 *d8 = vbout->bufmem + vbout->rowbytes * (hh + h2 + voffset);
uae_u32 *d32 = (uae_u32*)d8;
uae_u8 *s8 = vbin->bufmem + vbin->rowbytes * (hh + h2 + voffset) ;
uae_u32 *srcp = NULL;
if (sh >= 0 && sh < mpeg_height)
srcp = (uae_u32*)(mpeg_out_buffer + sh * mpeg_width * MPEG_PIXBYTES_32);
for (int ww = 0, sw = -hoffset; ww < w; sw++, ww += mult) {
uae_u32 sv = fmv_border_color;
if (sw >= 0 && sw < mpeg_width && srcp)
sv = srcp[sw];
for (int w2 = 0; w2 < mult; w2++) {
uae_u32 v;
if (s8[0] >= GENLOCK_VAL_32) {
v = *((uae_u32*)s8);
} else {
v = sv;
}
*d32++ = v;
s8 += d;
}
}
}
}
}
static void genlock_16(struct vidbuffer *vbin, struct vidbuffer *vbout, int w, int h, int d, int hoffset, int voffset, int mult)
{
for (int hh = 0, sh = -voffset; hh < h; sh++, hh += mult) {
for (int h2 = 0; h2 < mult; h2++) {
uae_u8 *d8 = vbout->bufmem + vbout->rowbytes * (hh + h2 + voffset);
uae_u16 *d16 = (uae_u16*)d8;
uae_u8 *s8 = vbin->bufmem + vbin->rowbytes * (hh + h2 + voffset) ;
uae_u16 *srcp = NULL;
if (sh >= 0 && sh < mpeg_height)
srcp = (uae_u16*)(mpeg_out_buffer + sh * mpeg_width * MPEG_PIXBYTES_16);
for (int ww = 0, sw = -hoffset; ww < w; sw++, ww += mult) {
uae_u16 sv = fmv_border_color_16;
if (sw >= 0 && sw < mpeg_width && srcp)
sv = srcp[sw];
for (int w2 = 0; w2 < mult; w2++) {
uae_u32 v;
if ((((uae_u16*)s8)[0] >> 11) >= GENLOCK_VAL_16) {
v = *((uae_u16*)s8);
} else {
v = sv;
}
*d16++ = v;
s8 += d;
}
}
}
}
}
void cd32_fmv_genlock(struct vidbuffer *vbin, struct vidbuffer *vbout)
{
int hoffset, voffset, mult;
int w = vbin->outwidth;
int h = vbin->outheight;
int d = vbin->pixbytes;
if (!mpeg_out_buffer)
return;
mult = 1;
for (;;) {
if (mult < 4 && mpeg_width * (mult << 1) <= w + 8 && mpeg_height * (mult << 1) <= h + 8) {
mult <<= 1;
}
else {
break;
}
}
hoffset = (w / mult - mpeg_width) / 2;
voffset = (h / mult - mpeg_height) / 2;
if (hoffset < 0)
hoffset = 0;
if (voffset < 0)
voffset = 0;
if (mpeg_depth == 2)
genlock_16(vbin, vbout, w, h, d, hoffset, voffset, mult);
else
genlock_32(vbin, vbout, w, h, d, hoffset, voffset, mult);
}