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