1 /*
2  *  KCemu -- The emulator for the KC85 homecomputer series and much more.
3  *  Copyright (C) 1997-2010 Torsten Paul
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 of the License, or
8  *  (at your option) 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 along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include "kc/system.h"
21 
22 #include "kc/kc.h"
23 #include "kc/gdc.h"
24 #include "kc/memory.h"
25 
26 #include "ui/generic/ui_0.h"
27 
UI_0(void)28 UI_0::UI_0(void)
29 {
30   _font = NULL;
31   _dirty = NULL;
32   _bitmap = NULL;
33   _pix_cache = NULL;
34   _col_cache = NULL;
35 
36   generic_set_mode(UI_GENERIC_MODE_Z1013_32x32);
37 
38   init();
39 }
40 
~UI_0(void)41 UI_0::~UI_0(void)
42 {
43   dispose();
44 }
45 
46 void
init(void)47 UI_0::init(void)
48 {
49   _dirty_size = (get_real_width() * get_real_height()) / 64;
50   _dirty = new byte_t[_dirty_size];
51   _bitmap = new byte_t[get_real_width() * get_real_height()];
52   _pix_cache = new byte_t[_dirty_size];
53   _col_cache = new byte_t[_dirty_size];
54 
55   memset(_dirty, 1, _dirty_size);
56   memset(_bitmap, 0, get_real_width() * get_real_height());
57 }
58 
59 void
dispose(void)60 UI_0::dispose(void)
61 {
62   if (_dirty)
63     delete[] _dirty;
64   if (_bitmap)
65     delete[] _bitmap;
66   if (_pix_cache)
67     delete[] _pix_cache;
68   if (_col_cache)
69     delete[] _col_cache;
70 }
71 
72 void
generic_put_pixels(byte_t * ptr,byte_t val,word_t color)73 UI_0::generic_put_pixels(byte_t *ptr, byte_t val, word_t color)
74 {
75   for (int a = 0;a < 8;a++)
76     ptr[a] = (val & (128 >> a)) ? (color >> 8) : color;
77 }
78 
79 void
generic_update_gdc(byte_t * font,bool clear_cache)80 UI_0::generic_update_gdc(byte_t *font, bool clear_cache)
81 {
82   if (gdc == NULL)
83     return;
84 
85   int a, x, y, z, p, c, fg, bg, col;
86   long offset = gdc->get_pram_SAD(0);
87 
88   int width = 80;
89   int height = 25;
90   int lines = 10;
91   int linecount = 0;
92   int subscreen = 0;
93 
94   byte_t *ptr = _bitmap;
95 
96   z = -1;
97   for (y = 0;y < height;y++)
98     {
99       if (linecount >= gdc->get_pram_LEN(subscreen))
100 	{
101 	  subscreen++;
102 	  linecount = 0;
103 	  offset = gdc->get_pram_SAD(subscreen) - z - 1; // compensate value of loop variable!
104 	}
105 
106       linecount += lines;
107 
108       for (x = 0;x < width;x++)
109 	{
110 	  z++;
111 	  p = gdc->get_mem(z + offset);
112 	  c = gdc->get_col(z + offset);
113 
114 	  _dirty[z] = clear_cache;
115 
116 	  if (p != _pix_cache[z])
117 	    {
118 	      _dirty[z]++;
119 	      _pix_cache[z] = p;
120 	    }
121 
122 	  if (c != _col_cache[z])
123 	    {
124 	      _dirty[z]++;
125 	      _col_cache[z] = c;
126 	    }
127 
128 	  if (gdc->get_cursor(z + offset))
129 	    {
130 	      _pix_cache[z] = 255; // invalidate cache on cursor position to force
131 	      _col_cache[z] = 255; // update there when cursor position changes
132 	    }
133 
134 	  if (!_dirty[z])
135 	    continue;
136 
137 	  fg = c & 15;
138 	  bg = (c >> 4) & 7;
139 
140 	  col = 0x0100;
141 	  if (p & 0x80)
142 	    {
143 	      p &= 0x7f;
144 	      col = 0x0001;
145 	    }
146 
147 	  ptr = _bitmap + y * 8 * 8 * width + 8 * x;
148           for (a = 0;a < 8;a++)
149 	    {
150 	      int xor_val = 0;
151 	      if (gdc->get_cursor(z + offset, a))
152 		xor_val = 0x0101;
153 	      generic_put_pixels(ptr + a * 8 * width, font[8 * p + a], col ^ xor_val);
154 	    }
155 	}
156     }
157 }
158 
159 void
generic_update_32x32(byte_t * font,bool clear_cache)160 UI_0::generic_update_32x32(byte_t *font, bool clear_cache)
161 {
162   byte_t pix;
163   int a, i, x, y, z, width, height;
164 
165   byte_t *irm = memory->get_irm();
166   byte_t *ptr = _bitmap;
167 
168   width = get_real_width();
169   height = get_real_height();
170 
171   i = -1;
172   z = 73;
173   ptr += 16 * width + 16;
174   for (y = 0;y < 256;y += 8)
175     {
176       for (x = 0;x < 256;x += 8)
177         {
178 	  i++;
179 	  z++;
180 
181 	  _dirty[z] = clear_cache;
182 
183 	  pix = irm[i];
184 	  if (_pix_cache[i] != pix)
185 	    _dirty[z]++;
186 
187 	  if (!_dirty[z])
188 	    continue;
189 
190 	  _pix_cache[i] = pix;
191           for (a = 0;a < 8;a++)
192             generic_put_pixels(ptr + a * width + x, font[8 * pix + a], 0x0100);
193 	}
194       z += 4;
195       ptr += 8 * width;
196     }
197 }
198 
199 void
generic_update_64x16(byte_t * font,bool clear_cache)200 UI_0::generic_update_64x16(byte_t *font, bool clear_cache)
201 {
202   byte_t pix;
203   int a, i, x, y, z, width, height, width8;
204 
205   byte_t *irm = memory->get_irm();
206   byte_t *ptr = _bitmap;
207 
208   width = get_real_width();
209   height = get_real_height();
210   width8 = width / 8;
211 
212   i = -1;
213   ptr += 6 * width + 8;
214   for (y = 0;y < 16;y++)
215     {
216       z = (((12 * y + 6) / 8) * width8);
217       for (x = 0;x < 512;x += 8)
218         {
219 	  i++;
220 	  z++;
221 
222 	  _dirty[z] = clear_cache;
223 
224 	  pix = irm[i];
225 	  if (_pix_cache[i] != pix)
226 	    _dirty[z]++;
227 
228 	  if (!_dirty[z])
229 	    continue;
230 
231 	  _dirty[z + width8]++;
232 
233 	  _pix_cache[i] = pix;
234           for (a = 0;a < 8;a++)
235             generic_put_pixels(ptr + a * width + x, font[8 * pix + a], 0x0100);
236 	}
237       ptr += 12 * width;
238     }
239 }
240 
241 void
generic_update(Scanline * scanline,MemAccess * memaccess,bool clear_cache)242 UI_0::generic_update(Scanline *scanline, MemAccess *memaccess, bool clear_cache)
243 {
244   byte_t *font = memory->get_char_rom();
245 
246   if (_font != font)
247     {
248       _font = font;
249       clear_cache = true;
250     }
251 
252   switch (_mode)
253     {
254     case UI_GENERIC_MODE_Z1013_32x32:
255       generic_update_32x32(font, clear_cache);
256       break;
257     case UI_GENERIC_MODE_Z1013_64x16:
258       generic_update_64x16(font, clear_cache);
259       break;
260     case UI_GENERIC_MODE_GDC:
261       generic_update_gdc(font, clear_cache);
262       break;
263     }
264 }
265 
266 void
generic_signal_v_retrace(bool value)267 UI_0::generic_signal_v_retrace(bool value)
268 {
269   if (_mode == UI_GENERIC_MODE_GDC)
270     if (gdc != NULL)
271       gdc->v_retrace(value);
272 }
273 
274 int
generic_get_mode(void)275 UI_0::generic_get_mode(void)
276 {
277   return _mode;
278 }
279 
280 void
generic_set_mode(int mode)281 UI_0::generic_set_mode(int mode)
282 {
283   _mode = mode;
284 
285   switch (_mode)
286     {
287     case UI_GENERIC_MODE_Z1013_32x32:
288       set_real_screen_size(288, 288);
289       break;
290     case UI_GENERIC_MODE_Z1013_64x16:
291       set_real_screen_size(528, 200);
292       break;
293     case UI_GENERIC_MODE_GDC:
294       set_real_screen_size(640, 200);
295       break;
296     }
297 
298   dispose();
299   init();
300 }
301