1 /***************************************************************************
2 
3   vidhrdw.c
4 
5   Functions to emulate the video hardware of the machine.
6 
7 ***************************************************************************/
8 
9 #include "driver.h"
10 #include "common.h"
11 #include "vidhrdw/generic.h"
12 
13 
14 
15 unsigned char *gottlieb_characterram;
16 #define MAX_CHARS 256
17 static unsigned char *dirtycharacter;
18 static int background_priority=0;
19 static unsigned char hflip=0;
20 static unsigned char vflip=0;
21 static int spritebank;
22 
23 
24 
25 /***************************************************************************
26 
27   Gottlieb games dosn't have a color PROM. They use 32 bytes of RAM to
28   dynamically create the palette. Each couple of bytes defines one
29   color (4 bits per pixel; the high 4 bits of the second byte are unused).
30 
31   The RAM is conected to the RGB output this way:
32 
33   bit 7 -- 240 ohm resistor  -- GREEN
34         -- 470 ohm resistor  -- GREEN
35         -- 1  kohm resistor  -- GREEN
36         -- 2  kohm resistor  -- GREEN
37         -- 240 ohm resistor  -- RED
38         -- 470 ohm resistor  -- RED
39         -- 1  kohm resistor  -- RED
40   bit 0 -- 2  kohm resistor  -- RED
41 
42   bit 7 -- unused
43         -- unused
44         -- unused
45         -- unused
46         -- 240 ohm resistor  -- BLUE
47         -- 470 ohm resistor  -- BLUE
48         -- 1  kohm resistor  -- BLUE
49   bit 0 -- 2  kohm resistor  -- BLUE
50 
51 ***************************************************************************/
WRITE_HANDLER(gottlieb_paletteram_w)52 WRITE_HANDLER( gottlieb_paletteram_w )
53 {
54 	int bit0,bit1,bit2,bit3;
55 	int r,g,b,val;
56 
57 
58 	paletteram[offset] = data;
59 
60 	/* red component */
61 	val = paletteram[offset | 1];
62 	bit0 = (val >> 0) & 0x01;
63 	bit1 = (val >> 1) & 0x01;
64 	bit2 = (val >> 2) & 0x01;
65 	bit3 = (val >> 3) & 0x01;
66 	r = 0x10 * bit0 + 0x21 * bit1 + 0x46 * bit2 + 0x88 * bit3;
67 
68 	/* green component */
69 	val = paletteram[offset & ~1];
70 	bit0 = (val >> 4) & 0x01;
71 	bit1 = (val >> 5) & 0x01;
72 	bit2 = (val >> 6) & 0x01;
73 	bit3 = (val >> 7) & 0x01;
74 	g = 0x10 * bit0 + 0x21 * bit1 + 0x46 * bit2 + 0x88 * bit3;
75 
76 	/* blue component */
77 	val = paletteram[offset & ~1];
78 	bit0 = (val >> 0) & 0x01;
79 	bit1 = (val >> 1) & 0x01;
80 	bit2 = (val >> 2) & 0x01;
81 	bit3 = (val >> 3) & 0x01;
82 	b = 0x10 * bit0 + 0x21 * bit1 + 0x46 * bit2 + 0x88 * bit3;
83 
84 	palette_change_color(offset / 2,r,g,b);
85 }
86 
87 
88 
89 /***************************************************************************
90 
91   Start the video hardware emulation.
92 
93 ***************************************************************************/
94 
gottlieb_vh_start(void)95 int gottlieb_vh_start(void)
96 {
97 	if (generic_vh_start() != 0)
98 		return 1;
99 
100 	if ((dirtycharacter = (unsigned char*)malloc(MAX_CHARS)) == 0)
101 	{
102 		generic_vh_stop();
103 		return 1;
104 	}
105 	/* Some games have character gfx data in ROM, some others in RAM. We don't */
106 	/* want to recalculate chars if data is in ROM, so let's start with the array */
107 	/* initialized to 0. */
108 	memset(dirtycharacter,0,MAX_CHARS);
109 
110 	return 0;
111 }
112 
113 /***************************************************************************
114 
115   Stop the video hardware emulation.
116 
117 ***************************************************************************/
gottlieb_vh_stop(void)118 void gottlieb_vh_stop(void)
119 {
120 	free(dirtycharacter);
121 	generic_vh_stop();
122 }
123 
124 
125 
WRITE_HANDLER(gottlieb_video_outputs_w)126 WRITE_HANDLER( gottlieb_video_outputs_w )
127 {
128 	extern void gottlieb_knocker(void);
129 	static int last = 0;
130 
131 
132 	background_priority = data & 1;
133 
134 	hflip = data & 2;
135 	vflip = data & 4;
136 	if ((data & 6) != (last & 6))
137 		memset(dirtybuffer,1,videoram_size);
138 
139 	/* in Q*Bert Qubes only, bit 4 controls the sprite bank */
140 	spritebank = (data & 0x10) >> 4;
141 
142 	if ((last&0x20) && !(data&0x20)) gottlieb_knocker();
143 
144 	last = data;
145 }
146 
WRITE_HANDLER(usvsthem_video_outputs_w)147 WRITE_HANDLER( usvsthem_video_outputs_w )
148 {
149 	background_priority = data & 1;
150 
151 	/* in most games, bits 1 and 2 flip screen, however in the laser */
152 	/* disc games they are different. */
153 
154 	/* bit 1 controls the sprite bank. */
155 	spritebank = (data & 0x02) >> 1;
156 
157 	/* bit 2 video enable (0 = black screen) */
158 
159 	/* bit 3 genlock control (1 = show laserdisc image) */
160 }
161 
162 
163 
WRITE_HANDLER(gottlieb_characterram_w)164 WRITE_HANDLER( gottlieb_characterram_w )
165 {
166 	if (gottlieb_characterram[offset] != data)
167 	{
168 		dirtycharacter[offset / 32] = 1;
169 		gottlieb_characterram[offset] = data;
170 	}
171 }
172 
173 
174 
175 /***************************************************************************
176 
177   Draw the game screen in the given osd_bitmap.
178   Do NOT call osd_update_display() from this function, it will be called by
179   the main emulation engine.
180 
181 ***************************************************************************/
gottlieb_vh_screenrefresh(struct osd_bitmap * bitmap,int full_refresh)182 void gottlieb_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh)
183 {
184     int offs;
185 
186 
187 	/* update palette */
188 	if (palette_recalc())
189 		memset(dirtybuffer, 1, videoram_size);
190 
191     /* recompute character graphics */
192     for (offs = 0;offs < Machine->drv->gfxdecodeinfo[0].gfxlayout->total;offs++)
193 	{
194 		if (dirtycharacter[offs])
195 			decodechar(Machine->gfx[0],offs,gottlieb_characterram,Machine->drv->gfxdecodeinfo[0].gfxlayout);
196 	}
197 
198 
199     /* for every character in the Video RAM, check if it has been modified */
200     /* since last time and update it accordingly. */
201     for (offs = videoram_size - 1;offs >= 0;offs--)
202 	{
203 		if (dirtybuffer[offs] || dirtycharacter[videoram[offs]])
204 		{
205 			int sx,sy;
206 
207 
208 			dirtybuffer[offs] = 0;
209 
210 			sx = offs % 32;
211 			sy = offs / 32;
212 			if (hflip) sx = 31 - sx;
213 			if (vflip) sy = 29 - sy;
214 
215 			drawgfx(tmpbitmap,Machine->gfx[0],
216 					videoram[offs],
217 					0,
218 					hflip,vflip,
219 					8*sx,8*sy,
220 					&Machine->visible_area,TRANSPARENCY_NONE,0);
221 		}
222     }
223 
224 	memset(dirtycharacter,0,MAX_CHARS);
225 
226 
227 	/* copy the character mapped graphics */
228 	copybitmap(bitmap,tmpbitmap,0,0,0,0,&Machine->visible_area,TRANSPARENCY_NONE,0);
229 
230 
231 	/* Draw the sprites. Note that it is important to draw them exactly in this */
232 	/* order, to have the correct priorities. */
233     for (offs = 0;offs < spriteram_size - 8;offs += 4)     /* it seems there's something strange with sprites #62 and #63 */
234 	{
235 	    int sx,sy;
236 
237 
238 		/* coordinates hand tuned to make the position correct in Q*Bert Qubes start */
239 		/* of level animation. */
240 		sx = (spriteram[offs + 1]) - 4;
241 		if (hflip) sx = 233 - sx;
242 		sy = (spriteram[offs]) - 13;
243 		if (vflip) sy = 228 - sy;
244 
245 		if (spriteram[offs] || spriteram[offs + 1])	/* needed to avoid garbage on screen */
246 			drawgfx(bitmap,Machine->gfx[1],
247 					(255 ^ spriteram[offs + 2]) + 256 * spritebank,
248 					0,
249 					hflip,vflip,
250 					sx,sy,
251 					&Machine->visible_area,
252 					background_priority ? TRANSPARENCY_THROUGH : TRANSPARENCY_PEN,
253 					background_priority ? Machine->pens[0]     : 0);
254 	}
255 }
256