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