1 /***************************************************************************
2 
3   vidhrdw.c
4 
5   Functions to emulate the video hardware of the machine.
6 
7 ***************************************************************************/
8 #include "driver.h"
9 #include "vidhrdw/generic.h"
10 
11 
12 static struct osd_bitmap *sprite_bm;
13 static struct osd_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_change_color(offset & 0x1f,r,g,b);
78 }
79 
80 
81 
82 /***************************************************************************
83 
84   Start the video hardware emulation.
85 
86 ***************************************************************************/
ccastles_vh_start(void)87 int ccastles_vh_start(void)
88 {
89 	if ((tmpbitmap = bitmap_alloc(Machine->drv->screen_width,Machine->drv->screen_height)) == 0)
90 		return 1;
91 
92 	if ((maskbitmap = bitmap_alloc(Machine->drv->screen_width,Machine->drv->screen_height)) == 0)
93 	{
94 		bitmap_free(tmpbitmap);
95 		return 1;
96 	}
97 
98 	if ((sprite_bm = bitmap_alloc(16,16)) == 0)
99 	{
100 		bitmap_free(maskbitmap);
101 		bitmap_free(tmpbitmap);
102 		return 1;
103 	}
104 
105 	return 0;
106 }
107 
108 
109 
110 /***************************************************************************
111 
112   Stop the video hardware emulation.
113 
114 ***************************************************************************/
ccastles_vh_stop(void)115 void ccastles_vh_stop(void)
116 {
117 	bitmap_free(sprite_bm);
118 	bitmap_free(maskbitmap);
119 	bitmap_free(tmpbitmap);
120 }
121 
122 
123 
READ_HANDLER(ccastles_bitmode_r)124 READ_HANDLER( ccastles_bitmode_r )
125 {
126 	int addr;
127 
128 	addr = (ccastles_screen_addr[1]<<7) | (ccastles_screen_addr[0]>>1);
129 
130 	/* is the address in videoram? */
131 	if ((addr >= 0x0c00) && (addr < 0x8000))
132 	{
133 		/* auto increment in the x-direction if it's enabled */
134 		if (!ccastles_screen_inc_enable[0])
135 		{
136 			if (!ccastles_screen_inc[0])
137 				ccastles_screen_addr[0] ++;
138 			else
139 				ccastles_screen_addr[0] --;
140 		}
141 
142 		/* auto increment in the y-direction if it's enabled */
143 		if (!ccastles_screen_inc_enable[1])
144 		{
145 			if (!ccastles_screen_inc[1])
146 				ccastles_screen_addr[1] ++;
147 			else
148 				ccastles_screen_addr[1] --;
149 		}
150 
151 		addr -= 0xc00;
152 		if (ccastles_screen_addr[0] & 0x01)
153 			return ((videoram[addr] & 0x0f) << 4);
154 		else
155 			return (videoram[addr] & 0xf0);
156 	}
157 
158 	return 0;
159 }
160 
WRITE_HANDLER(ccastles_bitmode_w)161 WRITE_HANDLER( ccastles_bitmode_w )
162 {
163 	int addr;
164 
165 
166 	addr = (ccastles_screen_addr[1] << 7) | (ccastles_screen_addr[0] >> 1);
167 
168 	/* is the address in videoram? */
169 	if ((addr >= 0x0c00) && (addr < 0x8000))
170 	{
171 		int x,y,j;
172 		int mode;
173 
174 		addr -= 0xc00;
175 
176 		if (ccastles_screen_addr[0] & 0x01)
177 		{
178 			mode = (data >> 4) & 0x0f;
179 			videoram[addr] = (videoram[addr] & 0xf0) | mode;
180 		}
181 		else
182 		{
183 			mode = (data & 0xf0);
184 			videoram[addr] = (videoram[addr] & 0x0f) | mode;
185 		}
186 
187 		j = 2*addr;
188 		x = j%256;
189 		y = j/256;
190 		if (!flip_screen)
191 		{
192 			plot_pixel(tmpbitmap, x  , y, Machine->pens[16 + ((videoram[addr] & 0xf0) >> 4)]);
193 			plot_pixel(tmpbitmap, x+1, y, Machine->pens[16 +  (videoram[addr] & 0x0f)      ]);
194 
195 			/* if bit 3 of the pixel is set, background has priority over sprites when */
196 			/* the sprite has the priority bit set. We use a second bitmap to remember */
197 			/* which pixels have priority. */
198 			plot_pixel(maskbitmap, x  , y, videoram[addr] & 0x80);
199 			plot_pixel(maskbitmap, x+1, y, videoram[addr] & 0x08);
200 		}
201 		else
202 		{
203 			y = 231-y;
204 			x = 254-x;
205 			if (y >= 0)
206 			{
207 				plot_pixel(tmpbitmap, x+1, y, Machine->pens[16 + ((videoram[addr] & 0xf0) >> 4)]);
208 				plot_pixel(tmpbitmap, x  , y, Machine->pens[16 +  (videoram[addr] & 0x0f)      ]);
209 
210 				/* if bit 3 of the pixel is set, background has priority over sprites when */
211 				/* the sprite has the priority bit set. We use a second bitmap to remember */
212 				/* which pixels have priority. */
213 				plot_pixel(maskbitmap, x+1, y, videoram[addr] & 0x80);
214 				plot_pixel(maskbitmap, x  , y, videoram[addr] & 0x08);
215 			}
216 		}
217 	}
218 
219 	/* auto increment in the x-direction if it's enabled */
220 	if (!ccastles_screen_inc_enable[0])
221 	{
222 		if (!ccastles_screen_inc[0])
223 			ccastles_screen_addr[0] ++;
224 		else
225 			ccastles_screen_addr[0] --;
226 	}
227 
228 	/* auto increment in the y-direction if it's enabled */
229 	if (!ccastles_screen_inc_enable[1])
230 	{
231 		if (!ccastles_screen_inc[1])
232 			ccastles_screen_addr[1] ++;
233 		else
234 			ccastles_screen_addr[1] --;
235 	}
236 
237 }
238 
239 
240 /***************************************************************************
241 
242   Draw the game screen in the given osd_bitmap.
243   Do NOT call osd_update_display() from this function, it will be called by
244   the main emulation engine.
245 
246 ***************************************************************************/
redraw_bitmap(void)247 static void redraw_bitmap(void)
248 {
249 	int x, y;
250 	int screen_addr0_save, screen_addr1_save, screen_inc_enable0_save, screen_inc_enable1_save;
251 
252 
253 	/* save out registers */
254 	screen_addr0_save = ccastles_screen_addr[0];
255 	screen_addr1_save = ccastles_screen_addr[1];
256 
257 	screen_inc_enable0_save = ccastles_screen_inc_enable[0];
258 	screen_inc_enable1_save = ccastles_screen_inc_enable[1];
259 
260 	ccastles_screen_inc_enable[0] = ccastles_screen_inc_enable[1] = 1;
261 
262 
263 	/* redraw bitmap */
264 	for (y = 0; y < 256; y++)
265 	{
266 		ccastles_screen_addr[1] = y;
267 
268 		for (x = 0; x < 256; x++)
269 		{
270 			ccastles_screen_addr[0] = x;
271 
272 			ccastles_bitmode_w(0, ccastles_bitmode_r(0));
273 		}
274 	}
275 
276 
277 	/* restore registers */
278 	ccastles_screen_addr[0] = screen_addr0_save;
279 	ccastles_screen_addr[1] = screen_addr1_save;
280 
281 	ccastles_screen_inc_enable[0] = screen_inc_enable0_save;
282 	ccastles_screen_inc_enable[1] = screen_inc_enable1_save;
283 }
284 
285 
ccastles_vh_screenrefresh(struct osd_bitmap * bitmap,int full_refresh)286 void ccastles_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh)
287 {
288 	int offs;
289 	unsigned char *spriteaddr;
290 	int scrollx,scrolly;
291 
292 
293 	if (palette_recalc() || full_refresh)
294 	{
295 		redraw_bitmap();
296 	}
297 
298 
299 	scrollx = 255 - *ccastles_scrollx;
300 	scrolly = 255 - *ccastles_scrolly;
301 
302 	if (flip_screen)
303 	{
304 		scrollx = 254 - scrollx;
305 		scrolly = 231 - scrolly;
306 	}
307 
308 	copyscrollbitmap(bitmap,tmpbitmap,1,&scrollx,1,&scrolly,
309 				     &Machine->visible_area,
310 		   			 TRANSPARENCY_NONE,0);
311 
312 
313 	if (*ccastles_sprite_bank)
314 		spriteaddr = spriteram;
315 	else
316 		spriteaddr = spriteram_2;
317 
318 
319 	/* Draw the sprites */
320 	for (offs = 0; offs < spriteram_size; offs += 4)
321 	{
322 		int i,j;
323 		int x,y;
324 
325 		/* Get the X and Y coordinates from the MOB RAM */
326 		x = spriteaddr[offs+3];
327 		y = 216 - spriteaddr[offs+1];
328 
329 		if (spriteaddr[offs+2] & 0x80)	/* background can have priority over the sprite */
330 		{
331 			fillbitmap(sprite_bm,Machine->gfx[0]->colortable[7],0);
332 			drawgfx(sprite_bm,Machine->gfx[0],
333 					spriteaddr[offs],1,
334 					flip_screen,flip_screen,
335 					0,0,
336 					0,TRANSPARENCY_PEN,7);
337 
338 			for (j = 0;j < 16;j++)
339 			{
340 				if (y + j >= 0)	/* avoid accesses out of the bitmap boundaries */
341 				{
342 					for (i = 0;i < 8;i++)
343 					{
344 						int pixa,pixb;
345 
346 						pixa = read_pixel(sprite_bm, i, j);
347 						pixb = read_pixel(maskbitmap, (x+scrollx+i)%256, (y+scrolly+j)%232);
348 
349 						/* if background has priority over sprite, make the */
350 						/* temporary bitmap transparent */
351 						if (pixb != 0 && (pixa != Machine->gfx[0]->colortable[0]))
352 							plot_pixel(sprite_bm, i, j, Machine->gfx[0]->colortable[7]);
353 					}
354 				}
355 			}
356 
357 			copybitmap(bitmap,sprite_bm,0,0,x,y,&Machine->visible_area,TRANSPARENCY_PEN,Machine->gfx[0]->colortable[7]);
358 		}
359 		else
360 		{
361 			drawgfx(bitmap,Machine->gfx[0],
362 					spriteaddr[offs],1,
363 					flip_screen,flip_screen,
364 					x,y,
365 					&Machine->visible_area,TRANSPARENCY_PEN,7);
366 		}
367 	}
368 }
369