1 /*
2 * TTTTTTTTTTTTTT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
3 * TTTTTTTTTTTTTT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
4 * TT EE OO OO
5 * TT EE OO OO
6 * TT EE OO OO
7 * TT EEEEEEEEEE OO OO
8 * TT EEEEEEEEEE OO OO
9 * TT EE OO OO
10 * TT EE OO OO
11 * TT EE OO OO
12 * TT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
13 * TT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
14 *
15 * L'�mulateur Thomson TO8
16 *
17 * Copyright (C) 1997-2017 Gilles F�tis, Eric Botcazou, Alexandre Pukall,
18 * J�r�mie Guillaume, Fran�ois Mouret,
19 * Samuel Devulder
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 */
35
36 /*
37 * Module : alleg/mode80.c
38 * Version : 1.8.4
39 * Cr�� par : Gilles F�tis
40 * Modifi� par: Eric Botcazou 24/10/2003
41 * Samuel Devulder 30/07/2011
42 * Fran�ois Mouret 25/04/2012 24/10/2012
43 *
44 * Gestion de l'affichage 80 colonnes du TO8.
45 */
46
47
48 #ifndef SCAN_DEPEND
49 #include <stdio.h>
50 #include <string.h>
51 #include <allegro.h>
52 #endif
53
54 #include "alleg/color8.h"
55 #include "alleg/gfxdrv.h"
56 #include "teo.h"
57
58
59 /* variables globales */
60 static int allegro_driver;
61 static int graphic_mode;
62 static BITMAP *gpl_buffer, *screen_buffer;
63 static int *dirty_cell;
64
65
66 #define PUT2PIXEL(val) *gpl_src++ = val; \
67 *gpl_src++ = val
68
69
70 /* gpl_need_update:
71 * Helper pour les dirty rectangles.
72 */
gpl_need_update(const unsigned char * gpl1,const unsigned char * gpl2)73 static inline int gpl_need_update(const unsigned char *gpl1, const unsigned char *gpl2)
74 {
75 register int i = TEO_GPL_SIZE*2;
76
77 while (i--)
78 if (*gpl1++ != *gpl2++)
79 return 1;
80
81 return 0;
82 }
83
84
85
86 /* DrawGPL:
87 * Affiche un Groupe Point Ligne (un octet de VRAM).
88 */
amode80_DrawGPL(int mode,int addr,int pt,int col)89 static void amode80_DrawGPL(int mode, int addr, int pt, int col)
90 {
91 register int i;
92 unsigned int c1, c2, x, y;
93 int *dirty_cell_row;
94 unsigned char *gpl_src = gpl_buffer->line[0], *gpl_dest;
95
96 switch (mode)
97 {
98 case TEO_BITMAP4: /* mode bitmap 4 couleurs */
99 pt<<=1;
100
101 for (i=0; i<8; i++)
102 {
103 c1 = bcell[((pt>>(7-i))&2)+((col>>(7-i))&1)].index;
104 PUT2PIXEL(c1);
105 }
106 break;
107
108 case TEO_PAGE1: /* mode commutation page 1 */
109 for (i=0; i<8; i++)
110 {
111 c1 = bcell[(0x80>>i)&pt ? 1 : 0].index;
112 PUT2PIXEL(c1);
113 }
114 break;
115
116 case TEO_PAGE2: /* mode commutation page 2 */
117 for (i=0; i<8; i++)
118 {
119 c1 = bcell[(0x80>>i)&pt ? 2 : 0].index;
120 PUT2PIXEL(c1);
121 }
122 break;
123
124 case TEO_STACK2: /* mode superposition 2 pages */
125 for (i=0; i<8; i++)
126 {
127 c1= bcell[(0x80>>i)&pt ? 1 : ((0x80>>i)&col ? 2 : 0)].index;
128 PUT2PIXEL(c1);
129 }
130 break;
131
132 case TEO_COL80: /* mode 80 colonnes */
133 for (i=0; i<8; i++)
134 *gpl_src++ = bcell[(0x80>>i)&pt ? 1 : 0].index;
135
136 for (i=0; i<8; i++)
137 *gpl_src++ = bcell[(0x80>>i)&col ? 1 : 0].index;
138
139 break;
140
141 case TEO_STACK4: /* mode superposition 4 pages */
142 /* on modifie les pixels 4 par 4 */
143 for (i=0; i<4; i++)
144 {
145 c1 = bcell[(0x80>>i)&pt ? 1 :
146 ((0x08>>i)&pt ? 2 :
147 ((0x80>>i)&col ? 3 :
148 ((0x08>>i)&col ? 4 : 0)))].index;
149 PUT2PIXEL(c1);
150 PUT2PIXEL(c1);
151 }
152 break;
153
154 case TEO_BITMAP4b: /* mode bitmap 4 non document� */
155 for (i=0;i<4;i++)
156 {
157 c1 = bcell[((pt>>(6-(i<<1)))&3)].index;
158 PUT2PIXEL(c1);
159 }
160
161 for (i=0;i<4;i++)
162 {
163 c1 = bcell[((col>>(6-(i<<1)))&3)].index;
164 PUT2PIXEL(c1);
165 }
166 break;
167
168 case TEO_BITMAP16: /* mode bitmap 16 couleurs */
169 /* on modifie les pixels 4 par 4 */
170 c1 = bcell[(pt&0xF0)>>4].index;
171 PUT2PIXEL(c1);
172 PUT2PIXEL(c1);
173
174 c1 = bcell[pt&0xF].index;
175 PUT2PIXEL(c1);
176 PUT2PIXEL(c1);
177
178 c1 = bcell[(col&0xF0)>>4].index;
179 PUT2PIXEL(c1);
180 PUT2PIXEL(c1);
181
182 c1 = bcell[col&0xF].index;
183 PUT2PIXEL(c1);
184 PUT2PIXEL(c1);
185 break;
186
187 case TEO_PALETTE: /* mode �cran de la palette */
188 if (addr<TEO_PALETTE_ADDR)
189 {
190 if ((col&0x78)==0x30)
191 {
192 c1=7;
193 c2=8;
194 }
195 else
196 {
197 c1=8;
198 c2=7;
199 }
200
201 for (i=0; i<8; i++)
202 {
203 col = (0x80>>i)&pt ? c1 : c2;
204 PUT2PIXEL(col);
205 }
206 break;
207 }
208 /* no break */
209
210 case TEO_COL40: /* mode 40 colonnes 16 couleurs */
211 default:
212 c1 = bcell[((col>>3)&7)+(((~col)&0x40)>>3)].index;
213 c2 = bcell[(col&7)+(((~col)&0x80)>>4)].index;
214
215 for (i=0; i<8; i++)
216 {
217 col = (0x80>>i)&pt ? c1 : c2;
218 PUT2PIXEL(col);
219 }
220 } /* end of switch */
221
222 x=(addr%TEO_WINDOW_GW)*TEO_GPL_SIZE*2;
223 y=(addr/TEO_WINDOW_GW)*2;
224
225 gpl_src = gpl_buffer->line[0];
226 gpl_dest = screen_buffer->line[y]+x;
227
228 if (gpl_need_update(gpl_src, gpl_dest))
229 {
230 /* duplication des pixels */
231 memcpy(gpl_dest, gpl_src, TEO_GPL_SIZE*2);
232 gpl_dest = screen_buffer->line[y+1]+x;
233 memcpy(gpl_dest, gpl_src, TEO_GPL_SIZE*2);
234
235 /* dirty rectangles */
236 x = addr%TEO_WINDOW_CW;
237 y = addr/(TEO_WINDOW_CW*TEO_CHAR_SIZE);
238 dirty_cell_row = dirty_cell + y*TEO_WINDOW_CW;
239 dirty_cell_row[x] = TRUE;
240 }
241 }
242
243
244
245 /* RetraceScreen:
246 * Rafra�chit une portion de l'�cran du TO8.
247 */
amode80_RetraceScreen(int x,int y,int width,int height)248 static inline void amode80_RetraceScreen(int x, int y, int width, int height)
249 {
250 blit(screen_buffer, screen, x, y, x, y, width, height);
251 }
252
END_OF_FUNCTION(amode80_RetraceScreen)253 END_OF_FUNCTION(amode80_RetraceScreen)
254
255
256
257 /* RefreshScreen:
258 * Rafra�chit l'�cran du TO8.
259 */
260 static void amode80_RefreshScreen(void)
261 {
262 register int i,j;
263 int cell_start;
264 int *dirty_cell_row = dirty_cell;
265 static int odd = 1;
266
267 if (!graphic_mode)
268 return;
269
270 acquire_screen();
271
272 if (teo.setting.interlaced_video)
273 {
274 odd ^= 1;
275 for(j=odd; j<TEO_WINDOW_H<<1; j+=2)
276 blit(screen_buffer, screen, 0, j, 0, j, TEO_WINDOW_W<<1, 1);
277 }
278 else
279 {
280 /* on groupe les dirty rectangles ligne par ligne */
281 for (j=0; j<TEO_WINDOW_CH; j++)
282 {
283 for (i=0; i<TEO_WINDOW_CW; i++)
284 if (dirty_cell_row[i])
285 {
286 cell_start=i;
287
288 while ((i<TEO_WINDOW_CW) && dirty_cell_row[i])
289 dirty_cell_row[i++]=FALSE;
290
291 amode80_RetraceScreen(cell_start*TEO_CHAR_SIZE*2, j*TEO_CHAR_SIZE*2,
292 (i-cell_start)*TEO_CHAR_SIZE*2, TEO_CHAR_SIZE*2);
293 }
294
295 /* ligne suivante */
296 dirty_cell_row += TEO_WINDOW_CW;
297 }
298 }
299
300 release_screen();
301 }
302
303
304
305 /* SetGraphicMode:
306 * S�lectionne le mode graphique de l'�mulateur.
307 */
amode80_SetGraphicMode(int mode)308 static int amode80_SetGraphicMode(int mode)
309 {
310 switch (mode)
311 {
312 case INIT:
313 if (set_gfx_mode(allegro_driver, TEO_WINDOW_W*2, TEO_WINDOW_H*2, 0, 0))
314 return FALSE;
315
316 acolor8_SetPalette();
317 graphic_mode=TRUE;
318 break;
319
320 case RESTORE:
321 set_gfx_mode(allegro_driver, TEO_WINDOW_W*2, TEO_WINDOW_H*2, 0, 0);
322 acolor8_SetPalette();
323 blit(screen_buffer, screen, 0, 0, 0, 0, TEO_WINDOW_W*2, TEO_WINDOW_H*2);
324 graphic_mode=TRUE;
325 break;
326
327 case SHUTDOWN:
328 acolor8_GetPalette(); /* on sauvegarde la palette */
329 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
330 graphic_mode=FALSE;
331 break;
332 }
333
334 return TRUE;
335 }
336
337
338 #define LED_SIZE 12
339
340
341 /* SetDiskLed:
342 * Allume/�teint la Led du lecteur de disquettes.
343 */
amode80_SetDiskLed(int led_on)344 static void amode80_SetDiskLed(int led_on)
345 {
346 static int count = 0;
347
348 if (graphic_mode)
349 {
350 if (led_on)
351 {
352 rect (screen, TEO_WINDOW_W*2-LED_SIZE,
353 0,
354 TEO_WINDOW_W*2-1,
355 LED_SIZE-1,
356 1);
357 rectfill(screen, TEO_WINDOW_W*2-LED_SIZE+1,
358 1,
359 TEO_WINDOW_W*2-2,
360 LED_SIZE-2,
361 6);
362 rect (screen, TEO_WINDOW_W*2-LED_SIZE+count,
363 count,
364 TEO_WINDOW_W*2-1-count,
365 LED_SIZE-1-count,
366 1);
367 count = (count+1)%(LED_SIZE/2);
368 }
369 else
370 RetraceScreen(TEO_WINDOW_W*2-LED_SIZE, 0, LED_SIZE, LED_SIZE);
371 }
372 }
373
374
375
376 /* InitGraphic:
377 * Initialise le pilote graphique 80 colonnes.
378 */
amode80_InitGraphic(int depth,int _allegro_driver,int border_support)379 static int amode80_InitGraphic(int depth, int _allegro_driver, int border_support)
380 {
381 if (depth != 8)
382 return FALSE;
383
384 set_color_depth(8);
385 acolor8_Init(FALSE);
386
387 allegro_driver = _allegro_driver;
388
389 if (!amode80_SetGraphicMode(INIT))
390 return FALSE;
391
392 gpl_buffer = create_bitmap(TEO_GPL_SIZE*2, 1);
393 screen_buffer = create_bitmap(TEO_WINDOW_W*2, TEO_WINDOW_H*2);
394 clear_bitmap(screen_buffer);
395 dirty_cell = calloc(TEO_WINDOW_CW*TEO_WINDOW_CH, sizeof(int));
396
397 /* objets touch�s par l'interruption souris (djgpp) */
398 LOCK_VARIABLE(screen_buffer);
399 LOCK_DATA(screen_buffer, sizeof(BITMAP));
400 LOCK_FUNCTION(amode80_RetraceScreen);
401
402 (void) border_support;
403
404 return TRUE;
405 }
406
407
408
409 struct GRAPHIC_DRIVER amode80_driver={
410 amode80_InitGraphic,
411 amode80_SetGraphicMode,
412 acolor8_RefreshPalette,
413 amode80_RefreshScreen,
414 amode80_RetraceScreen,
415 amode80_DrawGPL,
416 NULL,
417 acolor8_SetColor,
418 NULL,
419 amode80_SetDiskLed
420 };
421
422