1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004 Forgotten and the VBA development team
4 
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 
19 #include "screenarea.h"
20 
21 #include <cstring>
22 
23 namespace VBA
24 {
25 
ScreenArea(int _iWidth,int _iHeight,int _iScale)26 ScreenArea::ScreenArea(int _iWidth, int _iHeight, int _iScale) :
27   m_iFilterScale(1),
28   m_vFilter2x(NULL),
29   m_vFilterIB(NULL),
30   m_puiPixels(NULL),
31   m_puiDelta(NULL),
32   m_iScaledWidth(_iWidth),
33   m_iScaledHeight(_iHeight),
34   m_bEnableRender(true),
35   m_bShowCursor(true)
36 {
37   g_assert(_iWidth >= 1 && _iHeight >= 1 && _iScale >= 1);
38 
39   m_iWidth  = _iWidth;
40   m_iHeight = _iHeight;
41   m_iScale  = _iScale;
42 
43   set_events(Gdk::EXPOSURE_MASK
44              | Gdk::POINTER_MOTION_MASK
45              | Gdk::ENTER_NOTIFY_MASK
46              | Gdk::LEAVE_NOTIFY_MASK);
47 
48   char aiEmptyData[8];
49   memset(aiEmptyData, 0, sizeof(aiEmptyData));
50   Glib::RefPtr<Gdk::Bitmap> poSource = Gdk::Bitmap::create(aiEmptyData, 8, 8);
51   Glib::RefPtr<Gdk::Bitmap> poMask = Gdk::Bitmap::create(aiEmptyData, 8, 8);
52   Gdk::Color oFg;
53   Gdk::Color oBg;
54   oFg.set_rgb(0, 0, 0);
55   oBg.set_rgb(0, 0, 0);
56 
57   m_poEmptyCursor = new Gdk::Cursor(poSource, poMask, oFg, oBg, 0, 0);
58 }
59 
~ScreenArea()60 ScreenArea::~ScreenArea()
61 {
62   if (m_puiPixels)
63   {
64     delete[] m_puiPixels;
65   }
66 
67   if (m_puiDelta)
68   {
69     delete[] m_puiDelta;
70   }
71 
72   if (m_poEmptyCursor != NULL)
73   {
74     delete m_poEmptyCursor;
75   }
76 }
77 
vSetSize(int _iWidth,int _iHeight)78 void ScreenArea::vSetSize(int _iWidth, int _iHeight)
79 {
80   g_return_if_fail(_iWidth >= 1 && _iHeight >= 1);
81 
82   if (_iWidth != m_iWidth || _iHeight != m_iHeight)
83   {
84     m_iWidth  = _iWidth;
85     m_iHeight = _iHeight;
86     vUpdateSize();
87   }
88 }
89 
vSetScale(int _iScale)90 void ScreenArea::vSetScale(int _iScale)
91 {
92   g_return_if_fail(_iScale >= 1);
93 
94   if (_iScale == 1)
95   {
96     vSetFilter(FilterNone);
97   }
98 
99   m_iScale = _iScale;
100   vUpdateSize();
101 }
102 
vSetFilter(EFilter _eFilter)103 void ScreenArea::vSetFilter(EFilter _eFilter)
104 {
105   m_vFilter2x = pvGetFilter(_eFilter, FilterDepth32);
106 
107   m_iFilterScale = 1;
108   if (m_vFilter2x != NULL)
109   {
110     m_iFilterScale = 2;
111   }
112 
113   vUpdateSize();
114 }
115 
vSetFilterIB(EFilterIB _eFilterIB)116 void ScreenArea::vSetFilterIB(EFilterIB _eFilterIB)
117 {
118   m_vFilterIB = pvGetFilterIB(_eFilterIB, FilterDepth32);
119 }
120 
vStartCursorTimeout()121 void ScreenArea::vStartCursorTimeout()
122 {
123   m_oCursorSig.disconnect();
124   m_oCursorSig = Glib::signal_timeout().connect(
125     sigc::mem_fun(*this, &ScreenArea::bOnCursorTimeout),
126     2000);
127 }
128 
vStopCursorTimeout()129 void ScreenArea::vStopCursorTimeout()
130 {
131   m_oCursorSig.disconnect();
132 }
133 
vHideCursor()134 void ScreenArea::vHideCursor()
135 {
136   get_window()->set_cursor(*m_poEmptyCursor);
137   m_bShowCursor = false;
138 }
139 
vShowCursor()140 void ScreenArea::vShowCursor()
141 {
142   get_window()->set_cursor();
143   m_bShowCursor = true;
144 }
145 
on_motion_notify_event(GdkEventMotion * _pstEvent)146 bool ScreenArea::on_motion_notify_event(GdkEventMotion * _pstEvent)
147 {
148   if (! m_bShowCursor)
149   {
150     vShowCursor();
151   }
152   vStartCursorTimeout();
153   return false;
154 }
155 
on_enter_notify_event(GdkEventCrossing * _pstEvent)156 bool ScreenArea::on_enter_notify_event(GdkEventCrossing * _pstEvent)
157 {
158   vStartCursorTimeout();
159   return false;
160 }
161 
on_leave_notify_event(GdkEventCrossing * _pstEvent)162 bool ScreenArea::on_leave_notify_event(GdkEventCrossing * _pstEvent)
163 {
164   vStopCursorTimeout();
165   if (! m_bShowCursor)
166   {
167     vShowCursor();
168   }
169   return false;
170 }
171 
bOnCursorTimeout()172 bool ScreenArea::bOnCursorTimeout()
173 {
174   vHideCursor();
175   return false;
176 }
177 
vDrawPixels(u8 * _puiData)178 void ScreenArea::vDrawPixels(u8 * _puiData)
179 {
180   const int iSrcPitch = (m_iWidth + 1) * sizeof(u32);
181   const int iScaledPitch = (m_iScaledWidth + 1) * sizeof(u32);
182 
183   if (m_vFilterIB != NULL)
184   {
185     m_vFilterIB(_puiData + iSrcPitch,
186                 iSrcPitch,
187                 m_iWidth,
188                 m_iHeight);
189   }
190 
191   if (m_vFilter2x != NULL)
192   {
193     m_vFilter2x(_puiData + iSrcPitch,
194                 iSrcPitch,
195                 m_puiDelta,
196                 (u8 *)m_puiPixels,
197                 iScaledPitch,
198                 m_iWidth,
199                 m_iHeight);
200   }
201   else
202   {
203     memcpy(m_puiPixels, _puiData + iSrcPitch, m_iHeight * iSrcPitch);
204   }
205 }
206 
vUpdateSize()207 void ScreenArea::vUpdateSize()
208 {
209   if (m_puiPixels)
210   {
211     delete[] m_puiPixels;
212   }
213 
214   if (m_puiDelta)
215   {
216     delete[] m_puiDelta;
217   }
218 
219   m_iScaledWidth = m_iFilterScale * m_iWidth;
220   m_iScaledHeight = m_iFilterScale * m_iHeight;
221 
222   m_puiPixels = new u32[(m_iScaledWidth + 1) * m_iScaledHeight];
223   m_puiDelta = new u8[(m_iWidth + 2) * (m_iHeight + 2) * sizeof(u32)];
224   memset(m_puiPixels, 0, (m_iScaledWidth + 1) * m_iScaledHeight * sizeof(u32));
225   memset(m_puiDelta, 255, (m_iWidth + 2) * (m_iHeight + 2) * sizeof(u32));
226 
227   vOnSizeUpdated();
228 
229   set_size_request(m_iScale * m_iWidth, m_iScale * m_iHeight);
230 }
231 
on_configure_event(GdkEventConfigure * event)232 bool ScreenArea::on_configure_event(GdkEventConfigure * event)
233 {
234   vOnWidgetResize();
235 
236   return true;
237 }
238 
vSetEnableRender(bool _bEnable)239 void ScreenArea::vSetEnableRender(bool _bEnable)
240 {
241   m_bEnableRender = _bEnable;
242 }
243 
244 } // namespace VBA
245