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