Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/psx/octoshock/video/Deinterlacer.cpp
2 views
1
/* Mednafen - Multi-system Emulator
2
*
3
* This program is free software; you can redistribute it and/or modify
4
* it under the terms of the GNU General Public License as published by
5
* the Free Software Foundation; either version 2 of the License, or
6
* (at your option) any later version.
7
*
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
12
*
13
* You should have received a copy of the GNU General Public License
14
* along with this program; if not, write to the Free Software
15
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
*/
17
18
#include "octoshock.h"
19
#include "video.h"
20
21
#include "Deinterlacer.h"
22
23
Deinterlacer::Deinterlacer() : FieldBuffer(NULL), StateValid(false), DeintType(DEINT_WEAVE)
24
{
25
PrevDRect.x = 0;
26
PrevDRect.y = 0;
27
28
PrevDRect.w = 0;
29
PrevDRect.h = 0;
30
}
31
32
Deinterlacer::~Deinterlacer()
33
{
34
if(FieldBuffer)
35
{
36
delete FieldBuffer;
37
FieldBuffer = NULL;
38
}
39
}
40
41
void Deinterlacer::SetType(unsigned dt)
42
{
43
if(DeintType != dt)
44
{
45
DeintType = dt;
46
47
LWBuffer.resize(0);
48
if(FieldBuffer)
49
{
50
delete FieldBuffer;
51
FieldBuffer = NULL;
52
}
53
StateValid = false;
54
}
55
}
56
57
template<typename T>
58
void Deinterlacer::InternalProcess(MDFN_Surface *surface, MDFN_Rect &DisplayRect, int32 *LineWidths, const bool field)
59
{
60
//
61
// We need to output with LineWidths as always being valid to handle the case of horizontal resolution change between fields
62
// while in interlace mode, so clear the first LineWidths entry if it's == ~0, and
63
// [...]
64
const bool LineWidths_In_Valid = (LineWidths[0] != ~0);
65
const bool WeaveGood = (StateValid && PrevDRect.h == DisplayRect.h && DeintType == DEINT_WEAVE);
66
//
67
// XReposition stuff is to prevent exceeding the dimensions of the video surface under certain conditions(weave deinterlacer, previous field has higher
68
// horizontal resolution than current field, and current field's rectangle has an x offset that's too large when taking into consideration the previous field's
69
// width; for simplicity, we don't check widths, but just assume that the previous field's maximum width is >= than the current field's maximum width).
70
//
71
const int32 XReposition = ((WeaveGood && DisplayRect.x > PrevDRect.x) ? DisplayRect.x : 0);
72
73
//printf("%2d %2d, %d\n", DisplayRect.x, PrevDRect.x, XReposition);
74
75
if(XReposition)
76
DisplayRect.x = 0;
77
78
if(surface->h && !LineWidths_In_Valid)
79
{
80
LineWidths[0] = 0;
81
}
82
83
for(int y = 0; y < DisplayRect.h / 2; y++)
84
{
85
// [...]
86
// set all relevant source line widths to the contents of DisplayRect(also simplifies the src_lw and related pointer calculation code
87
// farther below.
88
if(!LineWidths_In_Valid)
89
LineWidths[(y * 2) + field + DisplayRect.y] = DisplayRect.w;
90
91
if(XReposition)
92
{
93
memmove(surface->pix<T>() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix,
94
surface->pix<T>() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + XReposition,
95
LineWidths[(y * 2) + field + DisplayRect.y] * sizeof(T));
96
}
97
98
if(WeaveGood)
99
{
100
const T* src = FieldBuffer->pix<T>() + y * FieldBuffer->pitchinpix;
101
T* dest = surface->pix<T>() + ((y * 2) + (field ^ 1) + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
102
int32 *dest_lw = &LineWidths[(y * 2) + (field ^ 1) + DisplayRect.y];
103
104
*dest_lw = LWBuffer[y];
105
106
memcpy(dest, src, LWBuffer[y] * sizeof(T));
107
}
108
else if(DeintType == DEINT_BOB)
109
{
110
const T* src = surface->pix<T>() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
111
T* dest = surface->pix<T>() + ((y * 2) + (field ^ 1) + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
112
const int32 *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y];
113
int32 *dest_lw = &LineWidths[(y * 2) + (field ^ 1) + DisplayRect.y];
114
115
*dest_lw = *src_lw;
116
117
memcpy(dest, src, *src_lw * sizeof(T));
118
}
119
else
120
{
121
const int32 *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y];
122
const T* src = surface->pix<T>() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
123
const int32 dly = ((y * 2) + (field + 1) + DisplayRect.y);
124
T* dest = surface->pix<T>() + dly * surface->pitchinpix + DisplayRect.x;
125
126
if(y == 0 && field)
127
{
128
T black = surface->MakeColor(0, 0, 0);
129
T* dm2 = surface->pix<T>() + (dly - 2) * surface->pitchinpix;
130
131
LineWidths[dly - 2] = *src_lw;
132
133
for(int x = 0; x < *src_lw; x++)
134
dm2[x] = black;
135
}
136
137
if(dly < (DisplayRect.y + DisplayRect.h))
138
{
139
LineWidths[dly] = *src_lw;
140
memcpy(dest, src, *src_lw * sizeof(T));
141
}
142
}
143
144
//
145
//
146
//
147
//
148
//
149
//
150
if(DeintType == DEINT_WEAVE)
151
{
152
const int32 *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y];
153
const T* src = surface->pix<T>() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
154
T* dest = FieldBuffer->pix<T>() + y * FieldBuffer->pitchinpix;
155
156
memcpy(dest, src, *src_lw * sizeof(uint32));
157
LWBuffer[y] = *src_lw;
158
159
StateValid = true;
160
}
161
}
162
}
163
164
void Deinterlacer::Process(MDFN_Surface *surface, MDFN_Rect &DisplayRect, int32 *LineWidths, const bool field)
165
{
166
const MDFN_Rect DisplayRect_Original = DisplayRect;
167
168
if(DeintType == DEINT_WEAVE)
169
{
170
if(!FieldBuffer || FieldBuffer->w < surface->w || FieldBuffer->h < (surface->h / 2))
171
{
172
if(FieldBuffer)
173
delete FieldBuffer;
174
175
FieldBuffer = new MDFN_Surface(NULL, surface->w, surface->h / 2, surface->w, surface->format);
176
LWBuffer.resize(FieldBuffer->h);
177
}
178
else if(memcmp(&surface->format, &FieldBuffer->format, sizeof(MDFN_PixelFormat)))
179
{
180
FieldBuffer->SetFormat(surface->format, StateValid && PrevDRect.h == DisplayRect.h);
181
}
182
}
183
184
switch(surface->format.bpp)
185
{
186
case 8:
187
InternalProcess<uint8>(surface, DisplayRect, LineWidths, field);
188
break;
189
190
case 16:
191
InternalProcess<uint16>(surface, DisplayRect, LineWidths, field);
192
break;
193
194
case 32:
195
InternalProcess<uint32>(surface, DisplayRect, LineWidths, field);
196
break;
197
}
198
199
PrevDRect = DisplayRect_Original;
200
}
201
202
void Deinterlacer::ClearState(void)
203
{
204
StateValid = false;
205
206
PrevDRect.x = 0;
207
PrevDRect.y = 0;
208
209
PrevDRect.w = 0;
210
PrevDRect.h = 0;
211
}
212
213