1 /***************************************************************************
2
3 vidhrdw.c
4
5 Functions to emulate the video hardware of the machine.
6
7 This file is used by the Pengo and Pac Man drivers.
8 They are almost identical, the only differences being the extra gfx bank
9 in Pengo, and the need to compensate for an hardware sprite positioning
10 "bug" in Pac Man.
11
12 ***************************************************************************/
13
14 #include "driver.h"
15 #include "vidhrdw/generic.h"
16
17
18
19 static int gfx_bank;
20 static int flipscreen;
21 static int xoffsethack;
22
23 static struct rectangle spritevisiblearea =
24 {
25 2*8, 34*8-1,
26 0*8, 28*8-1
27 };
28
29
30
31 /***************************************************************************
32
33 Convert the color PROMs into a more useable format.
34
35 Pac Man has a 32x8 palette PROM and a 256x4 color lookup table PROM.
36
37 Pengo has a 32x8 palette PROM and a 1024x4 color lookup table PROM.
38
39 The palette PROM is connected to the RGB output this way:
40
41 bit 7 -- 220 ohm resistor -- BLUE
42 -- 470 ohm resistor -- BLUE
43 -- 220 ohm resistor -- GREEN
44 -- 470 ohm resistor -- GREEN
45 -- 1 kohm resistor -- GREEN
46 -- 220 ohm resistor -- RED
47 -- 470 ohm resistor -- RED
48 bit 0 -- 1 kohm resistor -- RED
49
50 ***************************************************************************/
pacman_vh_convert_color_prom(unsigned char * palette,unsigned short * colortable,const unsigned char * color_prom)51 void pacman_vh_convert_color_prom(unsigned char *palette, unsigned short *colortable,const unsigned char *color_prom)
52 {
53 int i;
54 #define TOTAL_COLORS(gfxn) (Machine->gfx[gfxn]->total_colors * Machine->gfx[gfxn]->color_granularity)
55 #define COLOR(gfxn,offs) (colortable[Machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
56
57
58 for (i = 0;i < Machine->drv->total_colors;i++)
59 {
60 int bit0,bit1,bit2;
61
62
63 /* red component */
64 bit0 = (*color_prom >> 0) & 0x01;
65 bit1 = (*color_prom >> 1) & 0x01;
66 bit2 = (*color_prom >> 2) & 0x01;
67 *(palette++) = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
68 /* green component */
69 bit0 = (*color_prom >> 3) & 0x01;
70 bit1 = (*color_prom >> 4) & 0x01;
71 bit2 = (*color_prom >> 5) & 0x01;
72 *(palette++) = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
73 /* blue component */
74 bit0 = 0;
75 bit1 = (*color_prom >> 6) & 0x01;
76 bit2 = (*color_prom >> 7) & 0x01;
77 *(palette++) = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
78
79 color_prom++;
80 }
81
82 color_prom += 0x10;
83 /* color_prom now points to the beginning of the lookup table */
84
85 /* character lookup table */
86 /* sprites use the same color lookup table as characters */
87 for (i = 0;i < TOTAL_COLORS(0);i++)
88 COLOR(0,i) = *(color_prom++) & 0x0f;
89 }
90
pengo_vh_convert_color_prom(unsigned char * palette,unsigned short * colortable,const unsigned char * color_prom)91 void pengo_vh_convert_color_prom(unsigned char *palette, unsigned short *colortable,const unsigned char *color_prom)
92 {
93 int i;
94 #define TOTAL_COLORS(gfxn) (Machine->gfx[gfxn]->total_colors * Machine->gfx[gfxn]->color_granularity)
95 #define COLOR(gfxn,offs) (colortable[Machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
96
97
98 for (i = 0;i < Machine->drv->total_colors;i++)
99 {
100 int bit0,bit1,bit2;
101
102
103 /* red component */
104 bit0 = (*color_prom >> 0) & 0x01;
105 bit1 = (*color_prom >> 1) & 0x01;
106 bit2 = (*color_prom >> 2) & 0x01;
107 *(palette++) = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
108 /* green component */
109 bit0 = (*color_prom >> 3) & 0x01;
110 bit1 = (*color_prom >> 4) & 0x01;
111 bit2 = (*color_prom >> 5) & 0x01;
112 *(palette++) = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
113 /* blue component */
114 bit0 = 0;
115 bit1 = (*color_prom >> 6) & 0x01;
116 bit2 = (*color_prom >> 7) & 0x01;
117 *(palette++) = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
118
119 color_prom++;
120 }
121
122 /* color_prom now points to the beginning of the lookup table */
123
124 /* character lookup table */
125 /* sprites use the same color lookup table as characters */
126 for (i = 0;i < TOTAL_COLORS(0);i++)
127 COLOR(0,i) = *(color_prom++) & 0x0f;
128
129 color_prom += 0x80;
130
131 /* second bank character lookup table */
132 /* sprites use the same color lookup table as characters */
133 for (i = 0;i < TOTAL_COLORS(2);i++)
134 {
135 if (*color_prom) COLOR(2,i) = (*color_prom & 0x0f) + 0x10; /* second palette bank */
136 else COLOR(2,i) = 0; /* preserve transparency */
137
138 color_prom++;
139 }
140 }
141
142
143
144 /***************************************************************************
145
146 Start the video hardware emulation.
147
148 ***************************************************************************/
pengo_vh_start(void)149 int pengo_vh_start(void)
150 {
151 gfx_bank = 0;
152 xoffsethack = 0;
153
154 return generic_vh_start();
155 }
156
pacman_vh_start(void)157 int pacman_vh_start(void)
158 {
159 gfx_bank = 0;
160 /* In the Pac Man based games (NOT Pengo) the first two sprites must be offset */
161 /* one pixel to the left to get a more correct placement */
162 xoffsethack = 1;
163
164 return generic_vh_start();
165 }
166
167
168
WRITE_HANDLER(pengo_gfxbank_w)169 WRITE_HANDLER( pengo_gfxbank_w )
170 {
171 /* the Pengo hardware can set independently the palette bank, color lookup */
172 /* table, and chars/sprites. However the game always set them together (and */
173 /* the only place where this is used is the intro screen) so I don't bother */
174 /* emulating the whole thing. */
175 if (gfx_bank != (data & 1))
176 {
177 gfx_bank = data & 1;
178 memset(dirtybuffer,1,videoram_size);
179 }
180 }
181
WRITE_HANDLER(pengo_flipscreen_w)182 WRITE_HANDLER( pengo_flipscreen_w )
183 {
184 if (flipscreen != (data & 1))
185 {
186 flipscreen = data & 1;
187 memset(dirtybuffer,1,videoram_size);
188 }
189 }
190
191
192
193 /***************************************************************************
194
195 Draw the game screen in the given osd_bitmap.
196 Do NOT call osd_update_display() from this function, it will be called by
197 the main emulation engine.
198
199 ***************************************************************************/
pengo_vh_screenrefresh(struct osd_bitmap * bitmap,int full_refresh)200 void pengo_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh)
201 {
202 int offs;
203
204 for (offs = videoram_size - 1; offs > 0; offs--)
205 {
206 if (dirtybuffer[offs])
207 {
208 int mx,my,sx,sy;
209
210 dirtybuffer[offs] = 0;
211 mx = offs % 32;
212 my = offs / 32;
213
214 if (my < 2)
215 {
216 if (mx < 2 || mx >= 30) continue; /* not visible */
217 sx = my + 34;
218 sy = mx - 2;
219 }
220 else if (my >= 30)
221 {
222 if (mx < 2 || mx >= 30) continue; /* not visible */
223 sx = my - 30;
224 sy = mx - 2;
225 }
226 else
227 {
228 sx = mx + 2;
229 sy = my - 2;
230 }
231
232 if (flipscreen)
233 {
234 sx = 35 - sx;
235 sy = 27 - sy;
236 }
237
238 drawgfx(tmpbitmap,Machine->gfx[gfx_bank*2],
239 videoram[offs],
240 colorram[offs] & 0x1f,
241 flipscreen,flipscreen,
242 sx*8,sy*8,
243 &Machine->visible_area,TRANSPARENCY_NONE,0);
244 }
245 }
246
247 copybitmap(bitmap,tmpbitmap,0,0,0,0,&Machine->visible_area,TRANSPARENCY_NONE,0);
248
249 /* Draw the sprites. Note that it is important to draw them exactly in this */
250 /* order, to have the correct priorities. */
251 for (offs = spriteram_size - 2;offs > 2*2;offs -= 2)
252 {
253 int sx,sy;
254
255
256 sx = 272 - spriteram_2[offs + 1];
257 sy = spriteram_2[offs] - 31;
258
259 drawgfx(bitmap,Machine->gfx[gfx_bank*2+1],
260 spriteram[offs] >> 2,
261 spriteram[offs + 1] & 0x1f,
262 spriteram[offs] & 1,spriteram[offs] & 2,
263 sx,sy,
264 &spritevisiblearea,TRANSPARENCY_COLOR,0);
265
266 /* also plot the sprite with wraparound (tunnel in Crush Roller) */
267 drawgfx(bitmap,Machine->gfx[gfx_bank*2+1],
268 spriteram[offs] >> 2,
269 spriteram[offs + 1] & 0x1f,
270 spriteram[offs] & 1,spriteram[offs] & 2,
271 sx - 256,sy,
272 &spritevisiblearea,TRANSPARENCY_COLOR,0);
273 }
274 /* In the Pac Man based games (NOT Pengo) the first two sprites must be offset */
275 /* one pixel to the left to get a more correct placement */
276 for (offs = 2*2;offs >= 0;offs -= 2)
277 {
278 int sx,sy;
279
280
281 sx = 272 - spriteram_2[offs + 1];
282 sy = spriteram_2[offs] - 31;
283
284 drawgfx(bitmap,Machine->gfx[gfx_bank*2+1],
285 spriteram[offs] >> 2,
286 spriteram[offs + 1] & 0x1f,
287 spriteram[offs] & 1,spriteram[offs] & 2,
288 sx,sy + xoffsethack,
289 &spritevisiblearea,TRANSPARENCY_COLOR,0);
290
291 /* also plot the sprite with wraparound (tunnel in Crush Roller) */
292 drawgfx(bitmap,Machine->gfx[gfx_bank*2+1],
293 spriteram[offs] >> 2,
294 spriteram[offs + 1] & 0x1f,
295 spriteram[offs] & 2,spriteram[offs] & 1,
296 sx - 256,sy + xoffsethack,
297 &spritevisiblearea,TRANSPARENCY_COLOR,0);
298 }
299 }
300