1 /***************************************************************************
2 
3 	Atari Crystal Castles hardware
4 
5 ***************************************************************************/
6 
7 #include "driver.h"
8 #include "vidhrdw/generic.h"
9 #include "ccastles.h"
10 
11 
12 static struct mame_bitmap *sprite_bm;
13 static struct mame_bitmap *maskbitmap;
14 
15 unsigned char *ccastles_screen_addr;
16 unsigned char *ccastles_screen_inc;
17 unsigned char *ccastles_screen_inc_enable;
18 unsigned char *ccastles_sprite_bank;
19 unsigned char *ccastles_scrollx;
20 unsigned char *ccastles_scrolly;
21 
22 /***************************************************************************
23 
24   Convert the color PROMs into a more useable format.
25 
26   Crystal Castles doesn't have a color PROM. It uses RAM to dynamically
27   create the palette. The resolution is 9 bit (3 bits per gun). The palette
28   contains 32 entries, but it is accessed through a memory windows 64 bytes
29   long: writing to the first 32 bytes sets the msb of the red component to 0,
30   while writing to the last 32 bytes sets it to 1.
31   The first 16 entries are used for sprites; the last 16 for the background
32   bitmap.
33 
34   I don't know the exact values of the resistors between the RAM and the
35   RGB output, I assumed the usual ones.
36   bit 8 -- inverter -- 220 ohm resistor  -- RED
37   bit 7 -- inverter -- 470 ohm resistor  -- RED
38         -- inverter -- 1  kohm resistor  -- RED
39         -- inverter -- 220 ohm resistor  -- BLUE
40         -- inverter -- 470 ohm resistor  -- BLUE
41         -- inverter -- 1  kohm resistor  -- BLUE
42         -- inverter -- 220 ohm resistor  -- GREEN
43         -- inverter -- 470 ohm resistor  -- GREEN
44   bit 0 -- inverter -- 1  kohm resistor  -- GREEN
45 
46 ***************************************************************************/
WRITE_HANDLER(ccastles_paletteram_w)47 WRITE_HANDLER( ccastles_paletteram_w )
48 {
49 	int r,g,b;
50 	int bit0,bit1,bit2;
51 
52 
53 	r = (data & 0xC0) >> 6;
54 	b = (data & 0x38) >> 3;
55 	g = (data & 0x07);
56 	/* a write to offset 32-63 means to set the msb of the red component */
57 	if (offset & 0x20) r += 4;
58 
59 	/* bits are inverted */
60 	r = 7-r;
61 	g = 7-g;
62 	b = 7-b;
63 
64 	bit0 = (r >> 0) & 0x01;
65 	bit1 = (r >> 1) & 0x01;
66 	bit2 = (r >> 2) & 0x01;
67 	r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
68 	bit0 = (g >> 0) & 0x01;
69 	bit1 = (g >> 1) & 0x01;
70 	bit2 = (g >> 2) & 0x01;
71 	g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
72 	bit0 = (b >> 0) & 0x01;
73 	bit1 = (b >> 1) & 0x01;
74 	bit2 = (b >> 2) & 0x01;
75 	b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
76 
77 	palette_set_color(offset & 0x1f,r,g,b);
78 }
79 
80 
81 
82 /***************************************************************************
83 
84   Start the video hardware emulation.
85 
86 ***************************************************************************/
VIDEO_START(ccastles)87 VIDEO_START( ccastles )
88 {
89 	if ((tmpbitmap = auto_bitmap_alloc(Machine->drv->screen_width,Machine->drv->screen_height)) == 0)
90 		return 1;
91 
92 	if ((maskbitmap = auto_bitmap_alloc(Machine->drv->screen_width,Machine->drv->screen_height)) == 0)
93 		return 1;
94 
95 	if ((sprite_bm = auto_bitmap_alloc(8,16)) == 0)
96 		return 1;
97 
98 	return 0;
99 }
100 
101 
102 
READ_HANDLER(ccastles_bitmode_r)103 READ_HANDLER( ccastles_bitmode_r )
104 {
105 	int addr;
106 
107 	addr = (ccastles_screen_addr[1]<<7) | (ccastles_screen_addr[0]>>1);
108 
109 	/* is the address in videoram? */
110 	if ((addr >= 0x0c00) && (addr < 0x8000))
111 	{
112 		/* auto increment in the x-direction if it's enabled */
113 		if (!ccastles_screen_inc_enable[0])
114 		{
115 			if (!ccastles_screen_inc[0])
116 				ccastles_screen_addr[0] ++;
117 			else
118 				ccastles_screen_addr[0] --;
119 		}
120 
121 		/* auto increment in the y-direction if it's enabled */
122 		if (!ccastles_screen_inc_enable[1])
123 		{
124 			if (!ccastles_screen_inc[1])
125 				ccastles_screen_addr[1] ++;
126 			else
127 				ccastles_screen_addr[1] --;
128 		}
129 
130 		addr -= 0xc00;
131 		if (ccastles_screen_addr[0] & 0x01)
132 			return ((videoram[addr] & 0x0f) << 4);
133 		else
134 			return (videoram[addr] & 0xf0);
135 	}
136 
137 	return 0;
138 }
139 
WRITE_HANDLER(ccastles_bitmode_w)140 WRITE_HANDLER( ccastles_bitmode_w )
141 {
142 	int addr;
143 
144 
145 	addr = (ccastles_screen_addr[1] << 7) | (ccastles_screen_addr[0] >> 1);
146 
147 	/* is the address in videoram? */
148 	if ((addr >= 0x0c00) && (addr < 0x8000))
149 	{
150 		int x,y,j;
151 		int mode;
152 
153 		addr -= 0xc00;
154 
155 		if (ccastles_screen_addr[0] & 0x01)
156 		{
157 			mode = (data >> 4) & 0x0f;
158 			videoram[addr] = (videoram[addr] & 0xf0) | mode;
159 		}
160 		else
161 		{
162 			mode = (data & 0xf0);
163 			videoram[addr] = (videoram[addr] & 0x0f) | mode;
164 		}
165 
166 		j = 2*addr;
167 		x = j%256;
168 		y = j/256;
169 		if (!flip_screen)
170 		{
171 			plot_pixel(tmpbitmap, x  , y, Machine->pens[16 + ((videoram[addr] & 0xf0) >> 4)]);
172 			plot_pixel(tmpbitmap, x+1, y, Machine->pens[16 +  (videoram[addr] & 0x0f)      ]);
173 
174 			/* if bit 3 of the pixel is set, background has priority over sprites when */
175 			/* the sprite has the priority bit set. We use a second bitmap to remember */
176 			/* which pixels have priority. */
177 			plot_pixel(maskbitmap, x  , y, videoram[addr] & 0x80);
178 			plot_pixel(maskbitmap, x+1, y, videoram[addr] & 0x08);
179 		}
180 		else
181 		{
182 			y = 231-y;
183 			x = 254-x;
184 			if (y >= 0)
185 			{
186 				plot_pixel(tmpbitmap, x+1, y, Machine->pens[16 + ((videoram[addr] & 0xf0) >> 4)]);
187 				plot_pixel(tmpbitmap, x  , y, Machine->pens[16 +  (videoram[addr] & 0x0f)      ]);
188 
189 				/* if bit 3 of the pixel is set, background has priority over sprites when */
190 				/* the sprite has the priority bit set. We use a second bitmap to remember */
191 				/* which pixels have priority. */
192 				plot_pixel(maskbitmap, x+1, y, videoram[addr] & 0x80);
193 				plot_pixel(maskbitmap, x  , y, videoram[addr] & 0x08);
194 			}
195 		}
196 	}
197 
198 	/* auto increment in the x-direction if it's enabled */
199 	if (!ccastles_screen_inc_enable[0])
200 	{
201 		if (!ccastles_screen_inc[0])
202 			ccastles_screen_addr[0] ++;
203 		else
204 			ccastles_screen_addr[0] --;
205 	}
206 
207 	/* auto increment in the y-direction if it's enabled */
208 	if (!ccastles_screen_inc_enable[1])
209 	{
210 		if (!ccastles_screen_inc[1])
211 			ccastles_screen_addr[1] ++;
212 		else
213 			ccastles_screen_addr[1] --;
214 	}
215 
216 }
217 
218 
219 /***************************************************************************
220 
221   Draw the game screen in the given mame_bitmap.
222   Do NOT call osd_update_display() from this function, it will be called by
223   the main emulation engine.
224 
225 ***************************************************************************/
redraw_bitmap(void)226 static void redraw_bitmap(void)
227 {
228 	int x, y;
229 	int screen_addr0_save, screen_addr1_save, screen_inc_enable0_save, screen_inc_enable1_save;
230 
231 
232 	/* save out registers */
233 	screen_addr0_save = ccastles_screen_addr[0];
234 	screen_addr1_save = ccastles_screen_addr[1];
235 
236 	screen_inc_enable0_save = ccastles_screen_inc_enable[0];
237 	screen_inc_enable1_save = ccastles_screen_inc_enable[1];
238 
239 	ccastles_screen_inc_enable[0] = ccastles_screen_inc_enable[1] = 1;
240 
241 
242 	/* redraw bitmap */
243 	for (y = 0; y < 256; y++)
244 	{
245 		ccastles_screen_addr[1] = y;
246 
247 		for (x = 0; x < 256; x++)
248 		{
249 			ccastles_screen_addr[0] = x;
250 
251 			ccastles_bitmode_w(0, ccastles_bitmode_r(0));
252 		}
253 	}
254 
255 
256 	/* restore registers */
257 	ccastles_screen_addr[0] = screen_addr0_save;
258 	ccastles_screen_addr[1] = screen_addr1_save;
259 
260 	ccastles_screen_inc_enable[0] = screen_inc_enable0_save;
261 	ccastles_screen_inc_enable[1] = screen_inc_enable1_save;
262 }
263 
264 
VIDEO_UPDATE(ccastles)265 VIDEO_UPDATE( ccastles )
266 {
267 	int offs;
268 	unsigned char *spriteaddr;
269 	int scrollx,scrolly;
270 
271 
272 	if (get_vh_global_attribute_changed())
273 	{
274 		redraw_bitmap();
275 	}
276 
277 	scrollx = 255 - *ccastles_scrollx;
278 	scrolly = 255 - *ccastles_scrolly;
279 
280 	if (flip_screen)
281 	{
282 		scrollx = 254 - scrollx;
283 		scrolly = 231 - scrolly;
284 	}
285 
286 	copyscrollbitmap(bitmap,tmpbitmap,1,&scrollx,1,&scrolly,
287 				     cliprect,
288 		   			 TRANSPARENCY_NONE,0);
289 
290 
291 	if (*ccastles_sprite_bank)
292 		spriteaddr = spriteram;
293 	else
294 		spriteaddr = spriteram_2;
295 
296 
297 	/* Draw the sprites */
298 	for (offs = 0; offs < spriteram_size; offs += 4)
299 	{
300 		int i,j;
301 		int x,y;
302 
303 		/* Get the X and Y coordinates from the MOB RAM */
304 		x = spriteaddr[offs+3];
305 		y = 216 - spriteaddr[offs+1];
306 
307 		if (spriteaddr[offs+2] & 0x80)	/* background can have priority over the sprite */
308 		{
309 			drawgfx(sprite_bm,Machine->gfx[0],
310 					spriteaddr[offs],
311 					0,
312 					flip_screen,flip_screen,
313 					0,0,
314 					0,TRANSPARENCY_NONE,0);
315 
316 			for (j = 0;j < 16;j++)
317 			{
318 				if (y + j >= 0)	/* avoid accesses out of the bitmap boundaries */
319 				{
320 					for (i = 0;i < 8;i++)
321 					{
322 						int pixa,pixb;
323 
324 						pixa = read_pixel(sprite_bm, i, j);
325 						pixb = read_pixel(maskbitmap, (x-scrollx+i+256)%256, (y-scrolly+j+232)%232);
326 
327 						/* if background has priority over sprite, make the */
328 						/* temporary bitmap transparent */
329 						if (pixb != 0 && (pixa != Machine->pens[0]))
330 							plot_pixel(sprite_bm, i, j, Machine->pens[7]);
331 					}
332 				}
333 			}
334 
335 			copybitmap(bitmap,sprite_bm,0,0,x,y,cliprect,TRANSPARENCY_PEN,Machine->pens[7]);
336 		}
337 		else
338 		{
339 			drawgfx(bitmap,Machine->gfx[0],
340 					spriteaddr[offs],
341 					0,
342 					flip_screen,flip_screen,
343 					x,y,
344 					cliprect,TRANSPARENCY_PEN,7);
345 		}
346 	}
347 }
348