1 /***************************************************************************
2 
3 Custom blitter GA9201 KA01-0249 (120pin IC)
4 
5 
6 This is a tile-based blitter that writes to a frame buffer. The buffer is
7 never cleared, so stuff drawn is left over from frame to frame until it is
8 overwritten.
9 
10 Tiles are stored in ROM and have a fixed 16x16 size. The blitter can draw them
11 as single sprites (composed of one or more tiles in the horizontal direction),
12 or as larger sprites whose tile codes are picked from a tilemap in RAM.
13 
14 Sprites can be zoomed, distorted and rotated.
15 
16 Shadows are supported on pen 14 (shangha3 makes heavy use of them) but it's not
17 clear how they are turned on and off. heberpop definitely doesn't use them,
18 pen 14 is supposed to be solid black (outlines).
19 
20 The chip addresses 0x100000 bytes of memory, containing both the command list,
21 tilemap, and spare RAM to be used by the CPU.
22 
23 The command list starts at a variable point in memory, set by
24 shangha3_gfxlist_addr_w(), and always ends at 0x0fffff.
25 
26 Large sprites refer to a single tilemap starting at 0x000000, the command list
27 contains the coordinates of the place in the tilemap to pick data from.
28 
29 The commands list is processed when shangha3_blitter_go_w() is written to, so
30 it is not processed automatically every frame.
31 
32 The commands have a fixed length of 16 words. The format is as follows:
33 
34 Word | Bit(s)           | Use
35 -----+-fedcba9876543210-+----------------
36   0  | ---------------- | unused?
37   1  | xxxx------------ | high bits of tile #; for tilemaps, this is applied to all tiles
38   1  | ----xxxxxxxxxxxx | low bits of tile #; probably unused for tilemaps
39   2  | ---xxxxxxxxx---- | x coordinate of destination top left corner
40   3  | ---xxxxxxxxx---- | y coordinate of destination top left corner
41   4  | ------------x--- | 0 = use code as-is  1 = fetch codes from tilemap RAM
42   4  | -------------x-- | 1 = draw "compressed" tilemap, as if tiles were 8x8 instead of 16x16
43   4  | --------------x- | flip y
44   4  | ---------------x | flip x
45   5  | --------x------- | unknown (used by blocken)
46   5  | ---------xxx---- | high bits of color #; for tilemaps, this is applied to all tiles
47   5  | ------------xxxx | low bits of color #; probably unused for tilemaps
48   6  | xxxxxxxxxxxxxxxx | width-1 of destination rectangle    \ if *both* of these are 0,
49   7  | xxxxxxxxxxxxxxxx | height-1 of destination rectangle   / disable sprite
50   8  | xxxxxxxxxxxxxxxx | x coordinate*0x10 of source top left corner (tilemaps only?)
51   9  | xxxxxxxxxxxxxxxx | y coordinate*0x10 of source top left corner (tilemaps only?)
52   a  | xxxxxxxxxxxxxxxx | x zoom
53   b  | xxxxxxxxxxxxxxxx | rotation
54   c  | xxxxxxxxxxxxxxxx | rotation
55   d  | xxxxxxxxxxxxxxxx | x zoom
56   e  | ---------------- | unknown
57   f  | ---------------- | unknown
58 
59 ***************************************************************************/
60 
61 #include "driver.h"
62 #include "vidhrdw/generic.h"
63 
64 
65 data16_t *shangha3_ram;
66 size_t shangha3_ram_size;
67 
68 int shangha3_do_shadows;
69 
70 static data16_t gfxlist_addr;
71 static struct mame_bitmap *rawbitmap;
72 
73 
74 
VIDEO_START(shangha3)75 VIDEO_START( shangha3 )
76 {
77 	if ((rawbitmap = auto_bitmap_alloc(Machine->drv->screen_width,Machine->drv->screen_height)) == 0)
78 		return 1;
79 
80 	if (shangha3_do_shadows)
81 	{
82 		int i;
83 
84 		/* Prepare the shadow table */
85 		/* We draw in a raw bitmap so we don't have to remap pens through Machine->pens */
86 		for (i = 0;i < 14;i++)
87 			gfx_drawmode_table[i] = DRAWMODE_SOURCE;
88 		gfx_drawmode_table[14] = DRAWMODE_SHADOW;
89 		for (i = 0;i < 128;i++)
90 			palette_shadow_table[Machine->pens[i]] = Machine->pens[i+128];
91 	}
92 
93 	return 0;
94 }
95 
96 
97 
WRITE16_HANDLER(shangha3_flipscreen_w)98 WRITE16_HANDLER( shangha3_flipscreen_w )
99 {
100 	if (ACCESSING_LSB)
101 	{
102 		/* bit 7 flips screen, the rest seems to always be set to 0x7e */
103 		flip_screen_set(data & 0x80);
104 
105 		if ((data & 0x7f) != 0x7e) usrintf_showmessage("flipscreen_w %02x",data);
106 	}
107 }
108 
WRITE16_HANDLER(shangha3_gfxlist_addr_w)109 WRITE16_HANDLER( shangha3_gfxlist_addr_w )
110 {
111 	COMBINE_DATA(&gfxlist_addr);
112 }
113 
114 
WRITE16_HANDLER(shangha3_blitter_go_w)115 WRITE16_HANDLER( shangha3_blitter_go_w )
116 {
117 	int offs;
118 
119 
120 	profiler_mark(PROFILER_VIDEO);
121 
122 	for (offs = gfxlist_addr << 3;offs < shangha3_ram_size/2;offs += 16)
123 	{
124 		int sx,sy,x,y,code,color,flipx,flipy,sizex,sizey,zoomx,zoomy;
125 
126 
127 		code = shangha3_ram[offs+1];
128 		color = shangha3_ram[offs+5] & 0x7f;
129 		flipx = shangha3_ram[offs+4] & 0x01;
130 		flipy = shangha3_ram[offs+4] & 0x02;
131 		sx = (shangha3_ram[offs+2] & 0x1ff0) >> 4;
132 		if (sx >= 0x180) sx -= 0x200;
133 		sy = (shangha3_ram[offs+3] & 0x1ff0) >> 4;
134 		if (sy >= 0x100) sy -= 0x200;
135 		sizex = shangha3_ram[offs+6];
136 		sizey = shangha3_ram[offs+7];
137 		zoomx = shangha3_ram[offs+10];
138 		zoomy = shangha3_ram[offs+13];
139 
140 		if (flip_screen)
141 		{
142 			sx = 383 - sx - sizex;
143 			sy = 255 - sy - sizey;
144 			flipx = !flipx;
145 			flipy = !flipy;
146 		}
147 
148 		if ((sizex || sizey)
149 				/* avoid garbage on startup */
150 && sizex < 512 && sizey < 256 && zoomx < 0x1f0 && zoomy < 0x1f0)
151 		{
152 			struct rectangle myclip;
153 
154 /*if (shangha3_ram[offs+11] || shangha3_ram[offs+12])*/
155 /*logerror("offs %04x: sx %04x sy %04x zoom %04x %04x %04x %04x fx %d fy %d\n",offs,sx,sy,zoomx,shangha3_ram[offs+11]),shangha3_ram[offs+12],zoomy,flipx,flipy);*/
156 
157 			myclip.min_x = sx;
158 			myclip.max_x = sx + sizex;
159 			myclip.min_y = sy;
160 			myclip.max_y = sy + sizey;
161 
162 			if (shangha3_ram[offs+4] & 0x08)	/* tilemap */
163 			{
164 				int srcx,srcy,dispx,dispy,w,h,condensed;
165 
166 				condensed = shangha3_ram[offs+4] & 0x04;
167 
168 				srcx = shangha3_ram[offs+8]/16;
169 				srcy = shangha3_ram[offs+9]/16;
170 				dispx = srcx & 0x0f;
171 				dispy = srcy & 0x0f;
172 
173 				h = (sizey+15)/16+1;
174 				w = (sizex+15)/16+1;
175 
176 				if (condensed)
177 				{
178 					h *= 2;
179 					w *= 2;
180 					srcx /= 8;
181 					srcy /= 8;
182 				}
183 				else
184 				{
185 					srcx /= 16;
186 					srcy /= 16;
187 				}
188 
189 				for (y = 0;y < h;y++)
190 				{
191 					for (x = 0;x < w;x++)
192 					{
193 						int dx,dy,tile;
194 
195 						if (condensed)
196 						{
197 							int addr = ((y+srcy) & 0x1f) +
198 										0x20 * ((x+srcx) & 0xff);
199 							tile = shangha3_ram[addr];
200 							dx = 8*x*(0x200-zoomx)/0x100 - dispx;
201 							dy = 8*y*(0x200-zoomy)/0x100 - dispy;
202 						}
203 						else
204 						{
205 							int addr = ((y+srcy) & 0x0f) +
206 										0x10 * ((x+srcx) & 0xff) +
207 										0x100 * ((y+srcy) & 0x10);
208 							tile = shangha3_ram[addr];
209 							dx = 16*x*(0x200-zoomx)/0x100 - dispx;
210 							dy = 16*y*(0x200-zoomy)/0x100 - dispy;
211 						}
212 
213 						if (flipx) dx = sx + sizex-15 - dx;
214 						else dx = sx + dx;
215 						if (flipy) dy = sy + sizey-15 - dy;
216 						else dy = sy + dy;
217 
218 						drawgfx(rawbitmap,Machine->gfx[0],
219 								(tile & 0x0fff) | (code & 0xf000),
220 								(tile >> 12) | (color & 0x70),
221 								flipx,flipy,
222 								dx,dy,
223 								&myclip,TRANSPARENCY_PEN,15);
224 					}
225 				}
226 			}
227 			else	/* sprite */
228 			{
229 				int w;
230 
231 if (zoomx <= 1 && zoomy <= 1)
232 	drawgfxzoom(rawbitmap,Machine->gfx[0],
233 			code,
234 			color,
235 			flipx,flipy,
236 			sx,sy,
237 			&myclip,shangha3_do_shadows ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,15,
238 			0x1000000,0x1000000);
239 else
240 {
241 				w = (sizex+15)/16;
242 
243 				for (x = 0;x < w;x++)
244 				{
245 					drawgfxzoom(rawbitmap,Machine->gfx[0],
246 							code,
247 							color,
248 							flipx,flipy,
249 							sx + 16*x,sy,
250 							&myclip,shangha3_do_shadows ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,15,
251 							(0x200-zoomx)*0x100,(0x200-zoomy)*0x100);
252 
253 					if ((code & 0x000f) == 0x0f)
254 						code = (code + 0x100) & 0xfff0;
255 					else
256 						code++;
257 				}
258 }
259 			}
260 		}
261 	}
262 
263 	profiler_mark(PROFILER_END);
264 }
265 
266 
VIDEO_UPDATE(shangha3)267 VIDEO_UPDATE( shangha3 )
268 {
269 	copybitmap(bitmap,rawbitmap,0,0,0,0,&Machine->visible_area,TRANSPARENCY_NONE,0);
270 }
271