1
/* Mednafen - Multi-system Emulator
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.
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.
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
1
18
#include "video-common.h"
2
19
#include "Deinterlacer.h"
6
DEINT_BOB_OFFSET = 0, // Code will fall-through to this case under certain conditions, too.
11
static const unsigned DeintType = DEINT_WEAVE;
13
Deinterlacer::Deinterlacer()
21
Deinterlacer::Deinterlacer() : FieldBuffer(NULL), StateValid(false), DeintType(DEINT_WEAVE)
21
30
Deinterlacer::~Deinterlacer()
43
51
StateValid = false;
48
55
template<typename T>
49
void Deinterlacer::InternalProcess(MDFN_Surface *surface, const MDFN_Rect &DisplayRect, MDFN_Rect *LineWidths, const bool field)
56
void Deinterlacer::InternalProcess(MDFN_Surface *surface, MDFN_Rect &DisplayRect, int32 *LineWidths, const bool field)
52
59
// We need to output with LineWidths as always being valid to handle the case of horizontal resolution change between fields
53
60
// while in interlace mode, so clear the first LineWidths entry if it's == ~0, and
55
const bool LineWidths_In_Valid = (LineWidths[0].w != ~0);
62
const bool LineWidths_In_Valid = (LineWidths[0] != ~0);
63
const bool WeaveGood = (StateValid && PrevDRect.h == DisplayRect.h && DeintType == DEINT_WEAVE);
65
// XReposition stuff is to prevent exceeding the dimensions of the video surface under certain conditions(weave deinterlacer, previous field has higher
66
// 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
67
// 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).
69
const int32 XReposition = ((WeaveGood && DisplayRect.x > PrevDRect.x) ? DisplayRect.x : 0);
71
//printf("%2d %2d, %d\n", DisplayRect.x, PrevDRect.x, XReposition);
56
76
if(surface->h && !LineWidths_In_Valid)
62
81
for(int y = 0; y < DisplayRect.h / 2; y++)
65
84
// set all relevant source line widths to the contents of DisplayRect(also simplifies the src_lw and related pointer calculation code
67
86
if(!LineWidths_In_Valid)
68
LineWidths[(y * 2) + field + DisplayRect.y] = DisplayRect;
70
if(StateValid && PrevHeight == DisplayRect.h && DeintType == DEINT_WEAVE)
87
LineWidths[(y * 2) + field + DisplayRect.y] = DisplayRect.w;
91
memmove(surface->pix<T>() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix,
92
surface->pix<T>() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + XReposition,
93
LineWidths[(y * 2) + field + DisplayRect.y] * sizeof(T));
72
98
const T* src = FieldBuffer->pix<T>() + y * FieldBuffer->pitchinpix;
73
T* dest = surface->pix<T>() + ((y * 2) + (field ^ 1) + DisplayRect.y) * surface->pitchinpix;
74
MDFN_Rect *dest_lw = &LineWidths[(y * 2) + (field ^ 1) + DisplayRect.y];
99
T* dest = surface->pix<T>() + ((y * 2) + (field ^ 1) + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
100
int32 *dest_lw = &LineWidths[(y * 2) + (field ^ 1) + DisplayRect.y];
77
dest_lw->w = LWBuffer[y];
102
*dest_lw = LWBuffer[y];
79
104
memcpy(dest, src, LWBuffer[y] * sizeof(T));
81
106
else if(DeintType == DEINT_BOB)
83
const T* src = surface->pix<T>() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix;
84
T* dest = surface->pix<T>() + ((y * 2) + (field ^ 1) + DisplayRect.y) * surface->pitchinpix;
85
const MDFN_Rect *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y];
86
MDFN_Rect *dest_lw = &LineWidths[(y * 2) + (field ^ 1) + DisplayRect.y];
89
dest_lw->w = src_lw->w;
91
memcpy(dest, src + src_lw->x, src_lw->w * sizeof(T));
108
const T* src = surface->pix<T>() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
109
T* dest = surface->pix<T>() + ((y * 2) + (field ^ 1) + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
110
const int32 *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y];
111
int32 *dest_lw = &LineWidths[(y * 2) + (field ^ 1) + DisplayRect.y];
115
memcpy(dest, src, *src_lw * sizeof(T));
95
const MDFN_Rect *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y];
96
const T* src = surface->pix<T>() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + src_lw->x;
119
const int32 *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y];
120
const T* src = surface->pix<T>() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
97
121
const int32 dly = ((y * 2) + (field + 1) + DisplayRect.y);
98
T* dest = surface->pix<T>() + dly * surface->pitchinpix;
122
T* dest = surface->pix<T>() + dly * surface->pitchinpix + DisplayRect.x;
100
124
if(y == 0 && field)
105
129
LineWidths[dly - 2] = *src_lw;
107
for(int x = 0; x < src_lw->w; x++)
131
for(int x = 0; x < *src_lw; x++)
111
135
if(dly < (DisplayRect.y + DisplayRect.h))
113
137
LineWidths[dly] = *src_lw;
114
memcpy(dest, src, src_lw->w * sizeof(T));
138
memcpy(dest, src, *src_lw * sizeof(T));
124
148
if(DeintType == DEINT_WEAVE)
126
const MDFN_Rect *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y];
127
const T* src = surface->pix<T>() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + src_lw->x;
150
const int32 *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y];
151
const T* src = surface->pix<T>() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
128
152
T* dest = FieldBuffer->pix<T>() + y * FieldBuffer->pitchinpix;
130
memcpy(dest, src, src_lw->w * sizeof(uint32));
131
LWBuffer[y] = src_lw->w;
154
memcpy(dest, src, *src_lw * sizeof(uint32));
155
LWBuffer[y] = *src_lw;
133
157
StateValid = true;
137
PrevHeight = DisplayRect.h;
140
void Deinterlacer::Process(MDFN_Surface *surface, const MDFN_Rect &DisplayRect, MDFN_Rect *LineWidths, const bool field)
162
void Deinterlacer::Process(MDFN_Surface *surface, MDFN_Rect &DisplayRect, int32 *LineWidths, const bool field)
164
const MDFN_Rect DisplayRect_Original = DisplayRect;
142
166
if(DeintType == DEINT_WEAVE)
144
168
if(!FieldBuffer || FieldBuffer->w < surface->w || FieldBuffer->h < (surface->h / 2))
152
176
else if(memcmp(&surface->format, &FieldBuffer->format, sizeof(MDFN_PixelFormat)))
154
FieldBuffer->SetFormat(surface->format, StateValid && PrevHeight == DisplayRect.h);
178
FieldBuffer->SetFormat(surface->format, StateValid && PrevDRect.h == DisplayRect.h);