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