Backport GPU Unai plugin from PCSX4ALL
[pcsx_rearmed.git] / plugins / gpu_unai / gpu_command.h
1 /***************************************************************************
2 *   Copyright (C) 2010 PCSX4ALL Team                                      *
3 *   Copyright (C) 2010 Unai                                               *
4 *   Copyright (C) 2016 Senquack (dansilsby <AT> gmail <DOT> com)          *
5 *                                                                         *
6 *   This program is free software; you can redistribute it and/or modify  *
7 *   it under the terms of the GNU General Public License as published by  *
8 *   the Free Software Foundation; either version 2 of the License, or     *
9 *   (at your option) any later version.                                   *
10 *                                                                         *
11 *   This program is distributed in the hope that it will be useful,       *
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14 *   GNU General Public License for more details.                          *
15 *                                                                         *
16 *   You should have received a copy of the GNU General Public License     *
17 *   along with this program; if not, write to the                         *
18 *   Free Software Foundation, Inc.,                                       *
19 *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
20 ***************************************************************************/
21
22 ///////////////////////////////////////////////////////////////////////////////
23 void gpuSetTexture(u16 tpage)
24 {
25         u32 tmode, tx, ty;
26         gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x1FF) | (tpage & 0x1FF);
27         gpu_unai.TextureWindow[0]&= ~gpu_unai.TextureWindow[2];
28         gpu_unai.TextureWindow[1]&= ~gpu_unai.TextureWindow[3];
29
30         tmode = (tpage >> 7) & 3;  // 16bpp, 8bpp, or 4bpp texture colors?
31                                    // 0: 4bpp     1: 8bpp     2/3: 16bpp
32
33         // Nocash PSX docs state setting of 3 is same as setting of 2 (16bpp):
34         // Note: DrHell assumes 3 is same as 0.. TODO: verify which is correct?
35         if (tmode == 3) tmode = 2;
36
37         tx = (tpage & 0x0F) << 6;
38         ty = (tpage & 0x10) << 4;
39
40         tx += (gpu_unai.TextureWindow[0] >> (2 - tmode));
41         ty += gpu_unai.TextureWindow[1];
42         
43         gpu_unai.BLEND_MODE  = ((tpage>>5) & 3) << 3;
44         gpu_unai.TEXT_MODE   = (tmode + 1) << 5; // gpu_unai.TEXT_MODE should be values 1..3, so add one
45         gpu_unai.TBA = &((u16*)gpu_unai.vram)[FRAME_OFFSET(tx, ty)];
46 }
47
48 ///////////////////////////////////////////////////////////////////////////////
49 INLINE void gpuSetCLUT(u16 clut)
50 {
51         gpu_unai.CBA = &((u16*)gpu_unai.vram)[(clut & 0x7FFF) << 4];
52 }
53
54 #ifdef  ENABLE_GPU_NULL_SUPPORT
55 #define NULL_GPU() break
56 #else
57 #define NULL_GPU()
58 #endif
59
60 #ifdef  ENABLE_GPU_LOG_SUPPORT
61 #define DO_LOG(expr) printf expr
62 #else
63 #define DO_LOG(expr) {}
64 #endif
65
66 #define Blending      (((PRIM&0x2) && BlendingEnabled()) ? (PRIM&0x2) : 0)
67 #define Blending_Mode (((PRIM&0x2) && BlendingEnabled()) ? gpu_unai.BLEND_MODE : 0)
68 #define Lighting      (((~PRIM)&0x1) && LightingEnabled())
69 // Dithering applies only to Gouraud-shaded polys or texture-blended polys:
70 #define Dithering     (((((~PRIM)&0x1) || (PRIM&0x10)) && DitheringEnabled()) ?            \
71                        (ForcedDitheringEnabled() ? (1<<9) : (gpu_unai.GPU_GP1 & (1 << 9))) \
72                        : 0)
73
74 ///////////////////////////////////////////////////////////////////////////////
75 //Now handled by Rearmed's gpulib and gpu_unai/gpulib_if.cpp:
76 ///////////////////////////////////////////////////////////////////////////////
77 #ifndef USE_GPULIB
78
79 // Handles GP0 draw settings commands 0xE1...0xE6
80 static void gpuGP0Cmd_0xEx(gpu_unai_t &gpu_unai, u32 cmd_word)
81 {
82         // Assume incoming GP0 command is 0xE1..0xE6, convert to 1..6
83         u8 num = (cmd_word >> 24) & 7;
84         switch (num) {
85                 case 1: {
86                         // GP0(E1h) - Draw Mode setting (aka "Texpage")
87                         DO_LOG(("GP0(0xE1) DrawMode TexPage(0x%x)\n", cmd_word));
88                         u32 cur_texpage = gpu_unai.GPU_GP1 & 0x7FF;
89                         u32 new_texpage = cmd_word & 0x7FF;
90                         if (cur_texpage != new_texpage) {
91                                 gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x7FF) | new_texpage;
92                                 gpuSetTexture(gpu_unai.GPU_GP1);
93                         }
94                 } break;
95
96                 case 2: {
97                         // GP0(E2h) - Texture Window setting
98                         DO_LOG(("GP0(0xE2) TextureWindow(0x%x)\n", cmd_word));
99                         if (cmd_word != gpu_unai.TextureWindowCur) {
100                                 static const u8 TextureMask[32] = {
101                                         255, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7,
102                                         127, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7
103                                 };
104                                 gpu_unai.TextureWindowCur = cmd_word;
105                                 gpu_unai.TextureWindow[0] = ((cmd_word >> 10) & 0x1F) << 3;
106                                 gpu_unai.TextureWindow[1] = ((cmd_word >> 15) & 0x1F) << 3;
107                                 gpu_unai.TextureWindow[2] = TextureMask[(cmd_word >> 0) & 0x1F];
108                                 gpu_unai.TextureWindow[3] = TextureMask[(cmd_word >> 5) & 0x1F];
109                                 gpu_unai.TextureWindow[0] &= ~gpu_unai.TextureWindow[2];
110                                 gpu_unai.TextureWindow[1] &= ~gpu_unai.TextureWindow[3];
111
112                                 // Inner loop vars must be updated whenever texture window is changed:
113                                 const u32 fb = FIXED_BITS;  // # of fractional fixed-pt bits of u4/v4
114                                 gpu_unai.u_msk = (((u32)gpu_unai.TextureWindow[2]) << fb) | ((1 << fb) - 1);
115                                 gpu_unai.v_msk = (((u32)gpu_unai.TextureWindow[3]) << fb) | ((1 << fb) - 1);
116
117                                 gpuSetTexture(gpu_unai.GPU_GP1);
118                         }
119                 } break;
120
121                 case 3: {
122                         // GP0(E3h) - Set Drawing Area top left (X1,Y1)
123                         DO_LOG(("GP0(0xE3) DrawingArea Pos(0x%x)\n", cmd_word));
124                         gpu_unai.DrawingArea[0] = cmd_word         & 0x3FF;
125                         gpu_unai.DrawingArea[1] = (cmd_word >> 10) & 0x3FF;
126                 } break;
127
128                 case 4: {
129                         // GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
130                         DO_LOG(("GP0(0xE4) DrawingArea Size(0x%x)\n", cmd_word));
131                         gpu_unai.DrawingArea[2] = (cmd_word         & 0x3FF) + 1;
132                         gpu_unai.DrawingArea[3] = ((cmd_word >> 10) & 0x3FF) + 1;
133                 } break;
134
135                 case 5: {
136                         // GP0(E5h) - Set Drawing Offset (X,Y)
137                         DO_LOG(("GP0(0xE5) DrawingOffset(0x%x)\n", cmd_word));
138                         gpu_unai.DrawingOffset[0] = ((s32)cmd_word<<(32-11))>>(32-11);
139                         gpu_unai.DrawingOffset[1] = ((s32)cmd_word<<(32-22))>>(32-11);
140                 } break;
141
142                 case 6: {
143                         // GP0(E6h) - Mask Bit Setting
144                         DO_LOG(("GP0(0xE6) SetMask(0x%x)\n", cmd_word));
145                         gpu_unai.Masking  = (cmd_word & 0x2) <<  1;
146                         gpu_unai.PixelMSB = (cmd_word & 0x1) <<  8;
147                 } break;
148         }
149 }
150
151 void gpuSendPacketFunction(const int PRIM)
152 {
153         //printf("0x%x\n",PRIM);
154
155         //senquack - TODO: optimize this (packet pointer union as prim draw parameter
156         // introduced as optimization for gpulib command-list processing)
157         PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
158
159         switch (PRIM)
160         {
161                 case 0x02: {
162                         NULL_GPU();
163                         gpuClearImage(packet);    //  prim handles updateLace && skip
164                         gpu_unai.fb_dirty = true;
165                         DO_LOG(("gpuClearImage(0x%x)\n",PRIM));
166                 } break;
167
168                 case 0x20:
169                 case 0x21:
170                 case 0x22:
171                 case 0x23: {          // Monochrome 3-pt poly
172                         if (!gpu_unai.frameskip.skipGPU)
173                         {
174                                 NULL_GPU();
175                                 PP driver = gpuPolySpanDrivers[
176                                         (gpu_unai.blit_mask?1024:0) |
177                                         Blending_Mode |
178                                         gpu_unai.Masking | Blending | gpu_unai.PixelMSB
179                                 ];
180                                 gpuDrawPolyF(packet, driver, false);
181                                 gpu_unai.fb_dirty = true;
182                                 DO_LOG(("gpuDrawPolyF(0x%x)\n",PRIM));
183                         }
184                 } break;
185
186                 case 0x24:
187                 case 0x25:
188                 case 0x26:
189                 case 0x27: {          // Textured 3-pt poly
190                         if (!gpu_unai.frameskip.skipGPU)
191                         {
192                                 NULL_GPU();
193                                 gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
194                                 gpuSetTexture (gpu_unai.PacketBuffer.U4[4] >> 16);
195
196                                 u32 driver_idx =
197                                         (gpu_unai.blit_mask?1024:0) |
198                                         Dithering |
199                                         Blending_Mode | gpu_unai.TEXT_MODE |
200                                         gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
201
202                                 if (!FastLightingEnabled()) {
203                                         driver_idx |= Lighting;
204                                 } else {
205                                         if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
206                                                 driver_idx |= Lighting;
207                                 }
208
209                                 PP driver = gpuPolySpanDrivers[driver_idx];
210                                 gpuDrawPolyFT(packet, driver, false);
211                                 gpu_unai.fb_dirty = true;
212                                 DO_LOG(("gpuDrawPolyFT(0x%x)\n",PRIM));
213                         }
214                 } break;
215
216                 case 0x28:
217                 case 0x29:
218                 case 0x2A:
219                 case 0x2B: {          // Monochrome 4-pt poly
220                         if (!gpu_unai.frameskip.skipGPU)
221                         {
222                                 NULL_GPU();
223                                 PP driver = gpuPolySpanDrivers[
224                                         (gpu_unai.blit_mask?1024:0) |
225                                         Blending_Mode |
226                                         gpu_unai.Masking | Blending | gpu_unai.PixelMSB
227                                 ];
228                                 gpuDrawPolyF(packet, driver, true); // is_quad = true
229                                 gpu_unai.fb_dirty = true;
230                                 DO_LOG(("gpuDrawPolyF(0x%x) (4-pt QUAD)\n",PRIM));
231                         }
232                 } break;
233
234                 case 0x2C:
235                 case 0x2D:
236                 case 0x2E:
237                 case 0x2F: {          // Textured 4-pt poly
238                         if (!gpu_unai.frameskip.skipGPU)
239                         {
240                                 NULL_GPU();
241                                 gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
242                                 gpuSetTexture (gpu_unai.PacketBuffer.U4[4] >> 16);
243
244                                 u32 driver_idx =
245                                         (gpu_unai.blit_mask?1024:0) |
246                                         Dithering |
247                                         Blending_Mode | gpu_unai.TEXT_MODE |
248                                         gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
249
250                                 if (!FastLightingEnabled()) {
251                                         driver_idx |= Lighting;
252                                 } else {
253                                         if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
254                                                 driver_idx |= Lighting;
255                                 }
256
257                                 PP driver = gpuPolySpanDrivers[driver_idx];
258                                 gpuDrawPolyFT(packet, driver, true); // is_quad = true
259                                 gpu_unai.fb_dirty = true;
260                                 DO_LOG(("gpuDrawPolyFT(0x%x) (4-pt QUAD)\n",PRIM));
261                         }
262                 } break;
263
264                 case 0x30:
265                 case 0x31:
266                 case 0x32:
267                 case 0x33: {          // Gouraud-shaded 3-pt poly
268                         if (!gpu_unai.frameskip.skipGPU)
269                         {
270                                 NULL_GPU();
271                                 //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
272                                 // this is an untextured poly, so CF_LIGHT (texture blend)
273                                 // shouldn't apply. Until the original array of template
274                                 // instantiation ptrs is fixed, we're stuck with this. (TODO)
275                                 PP driver = gpuPolySpanDrivers[
276                                         (gpu_unai.blit_mask?1024:0) |
277                                         Dithering |
278                                         Blending_Mode |
279                                         gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
280                                 ];
281                                 gpuDrawPolyG(packet, driver, false);
282                                 gpu_unai.fb_dirty = true;
283                                 DO_LOG(("gpuDrawPolyG(0x%x)\n",PRIM));
284                         }
285                 } break;
286
287                 case 0x34:
288                 case 0x35:
289                 case 0x36:
290                 case 0x37: {          // Gouraud-shaded, textured 3-pt poly
291                         if (!gpu_unai.frameskip.skipGPU)
292                         {
293                                 NULL_GPU();
294                                 gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
295                                 gpuSetTexture (gpu_unai.PacketBuffer.U4[5] >> 16);
296                                 PP driver = gpuPolySpanDrivers[
297                                         (gpu_unai.blit_mask?1024:0) |
298                                         Dithering |
299                                         Blending_Mode | gpu_unai.TEXT_MODE |
300                                         gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
301                                 ];
302                                 gpuDrawPolyGT(packet, driver, false);
303                                 gpu_unai.fb_dirty = true;
304                                 DO_LOG(("gpuDrawPolyGT(0x%x)\n",PRIM));
305                         }
306                 } break;
307
308                 case 0x38:
309                 case 0x39:
310                 case 0x3A:
311                 case 0x3B: {          // Gouraud-shaded 4-pt poly
312                         if (!gpu_unai.frameskip.skipGPU)
313                         {
314                                 NULL_GPU();
315                                 // See notes regarding '129' for 0x30..0x33 further above -senquack
316                                 PP driver = gpuPolySpanDrivers[
317                                         (gpu_unai.blit_mask?1024:0) |
318                                         Dithering |
319                                         Blending_Mode |
320                                         gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
321                                 ];
322                                 gpuDrawPolyG(packet, driver, true); // is_quad = true
323                                 gpu_unai.fb_dirty = true;
324                                 DO_LOG(("gpuDrawPolyG(0x%x) (4-pt QUAD)\n",PRIM));
325                         }
326                 } break;
327
328                 case 0x3C:
329                 case 0x3D:
330                 case 0x3E:
331                 case 0x3F: {          // Gouraud-shaded, textured 4-pt poly
332                         if (!gpu_unai.frameskip.skipGPU)
333                         {
334                                 NULL_GPU();
335                                 gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
336                                 gpuSetTexture (gpu_unai.PacketBuffer.U4[5] >> 16);
337                                 PP driver = gpuPolySpanDrivers[
338                                         (gpu_unai.blit_mask?1024:0) |
339                                         Dithering |
340                                         Blending_Mode | gpu_unai.TEXT_MODE |
341                                         gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
342                                 ];
343                                 gpuDrawPolyGT(packet, driver, true); // is_quad = true
344                                 gpu_unai.fb_dirty = true;
345                                 DO_LOG(("gpuDrawPolyGT(0x%x) (4-pt QUAD)\n",PRIM));
346                         }
347                 } break;
348
349                 case 0x40:
350                 case 0x41:
351                 case 0x42:
352                 case 0x43: {          // Monochrome line
353                         if (!gpu_unai.frameskip.skipGPU)
354                         {
355                                 NULL_GPU();
356                                 // Shift index right by one, as untextured prims don't use lighting
357                                 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
358                                 PSD driver = gpuPixelSpanDrivers[driver_idx];
359                                 gpuDrawLineF(packet, driver);
360                                 gpu_unai.fb_dirty = true;
361                                 DO_LOG(("gpuDrawLineF(0x%x)\n",PRIM));
362                         }
363                 } break;
364
365                 case 0x48:
366                 case 0x49:
367                 case 0x4A:
368                 case 0x4B:
369                 case 0x4C:
370                 case 0x4D:
371                 case 0x4E:
372                 case 0x4F: { // Monochrome line strip
373                         if (!gpu_unai.frameskip.skipGPU)
374                         {
375                                 NULL_GPU();
376                                 // Shift index right by one, as untextured prims don't use lighting
377                                 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
378                                 PSD driver = gpuPixelSpanDrivers[driver_idx];
379                                 gpuDrawLineF(packet, driver);
380                                 gpu_unai.fb_dirty = true;
381                                 DO_LOG(("gpuDrawLineF(0x%x)\n",PRIM));
382                         }
383                         if ((gpu_unai.PacketBuffer.U4[3] & 0xF000F000) != 0x50005000)
384                         {
385                                 gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[2];
386                                 gpu_unai.PacketBuffer.U4[2] = gpu_unai.PacketBuffer.U4[3];
387                                 gpu_unai.PacketCount = 1;
388                                 gpu_unai.PacketIndex = 3;
389                         }
390                 } break;
391
392                 case 0x50:
393                 case 0x51:
394                 case 0x52:
395                 case 0x53: {          // Gouraud-shaded line
396                         if (!gpu_unai.frameskip.skipGPU)
397                         {
398                                 NULL_GPU();
399                                 // Shift index right by one, as untextured prims don't use lighting
400                                 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
401                                 // Index MSB selects Gouraud-shaded PixelSpanDriver:
402                                 driver_idx |= (1 << 5);
403                                 PSD driver = gpuPixelSpanDrivers[driver_idx];
404                                 gpuDrawLineG(packet, driver);
405                                 gpu_unai.fb_dirty = true;
406                                 DO_LOG(("gpuDrawLineG(0x%x)\n",PRIM));
407                         }
408                 } break;
409
410                 case 0x58:
411                 case 0x59:
412                 case 0x5A:
413                 case 0x5B:
414                 case 0x5C:
415                 case 0x5D:
416                 case 0x5E:
417                 case 0x5F: { // Gouraud-shaded line strip
418                         if (!gpu_unai.frameskip.skipGPU)
419                         {
420                                 NULL_GPU();
421                                 // Shift index right by one, as untextured prims don't use lighting
422                                 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
423                                 // Index MSB selects Gouraud-shaded PixelSpanDriver:
424                                 driver_idx |= (1 << 5);
425                                 PSD driver = gpuPixelSpanDrivers[driver_idx];
426                                 gpuDrawLineG(packet, driver);
427                                 gpu_unai.fb_dirty = true;
428                                 DO_LOG(("gpuDrawLineG(0x%x)\n",PRIM));
429                         }
430                         if ((gpu_unai.PacketBuffer.U4[4] & 0xF000F000) != 0x50005000)
431                         {
432                                 gpu_unai.PacketBuffer.U1[3 + (2 * 4)] = gpu_unai.PacketBuffer.U1[3 + (0 * 4)];
433                                 gpu_unai.PacketBuffer.U4[0] = gpu_unai.PacketBuffer.U4[2];
434                                 gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[3];
435                                 gpu_unai.PacketBuffer.U4[2] = gpu_unai.PacketBuffer.U4[4];
436                                 gpu_unai.PacketCount = 2;
437                                 gpu_unai.PacketIndex = 3;
438                         }
439                 } break;
440
441                 case 0x60:
442                 case 0x61:
443                 case 0x62:
444                 case 0x63: {          // Monochrome rectangle (variable size)
445                         if (!gpu_unai.frameskip.skipGPU)
446                         {
447                                 NULL_GPU();
448                                 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
449                                 gpuDrawT(packet, driver);
450                                 gpu_unai.fb_dirty = true;
451                                 DO_LOG(("gpuDrawT(0x%x)\n",PRIM));
452                         }
453                 } break;
454
455                 case 0x64:
456                 case 0x65:
457                 case 0x66:
458                 case 0x67: {          // Textured rectangle (variable size)
459                         if (!gpu_unai.frameskip.skipGPU)
460                         {
461                                 NULL_GPU();
462                                 gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
463                                 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
464
465                                 // This fixes Silent Hill running animation on loading screens:
466                                 // (On PSX, color values 0x00-0x7F darken the source texture's color,
467                                 //  0x81-FF lighten textures (ultimately clamped to 0x1F),
468                                 //  0x80 leaves source texture color unchanged, HOWEVER,
469                                 //   gpu_unai uses a simple lighting LUT whereby only the upper
470                                 //   5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
471                                 //   0x80.
472                                 // 
473                                 // NOTE: I've changed all textured sprite draw commands here and
474                                 //  elsewhere to use proper behavior, but left poly commands
475                                 //  alone, I don't want to slow rendering down too much. (TODO)
476                                 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
477                                 // Strip lower 3 bits of each color and determine if lighting should be used:
478                                 if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
479                                         driver_idx |= Lighting;
480                                 PS driver = gpuSpriteSpanDrivers[driver_idx];
481                                 gpuDrawS(packet, driver);
482                                 gpu_unai.fb_dirty = true;
483                                 DO_LOG(("gpuDrawS(0x%x)\n",PRIM));
484                         }
485                 } break;
486
487                 case 0x68:
488                 case 0x69:
489                 case 0x6A:
490                 case 0x6B: {          // Monochrome rectangle (1x1 dot)
491                         if (!gpu_unai.frameskip.skipGPU)
492                         {
493                                 NULL_GPU();
494                                 gpu_unai.PacketBuffer.U4[2] = 0x00010001;
495                                 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
496                                 gpuDrawT(packet, driver);
497                                 gpu_unai.fb_dirty = true;
498                                 DO_LOG(("gpuDrawT(0x%x)\n",PRIM));
499                         }
500                 } break;
501
502                 case 0x70:
503                 case 0x71:
504                 case 0x72:
505                 case 0x73: {          // Monochrome rectangle (8x8)
506                         if (!gpu_unai.frameskip.skipGPU)
507                         {
508                                 NULL_GPU();
509                                 gpu_unai.PacketBuffer.U4[2] = 0x00080008;
510                                 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
511                                 gpuDrawT(packet, driver);
512                                 gpu_unai.fb_dirty = true;
513                                 DO_LOG(("gpuDrawT(0x%x)\n",PRIM));
514                         }
515                 } break;
516
517                 case 0x74:
518                 case 0x75:
519                 case 0x76:
520                 case 0x77: {          // Textured rectangle (8x8)
521                         if (!gpu_unai.frameskip.skipGPU)
522                         {
523                                 NULL_GPU();
524                                 gpu_unai.PacketBuffer.U4[3] = 0x00080008;
525                                 gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
526                                 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
527
528                                 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
529                                 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
530                                 // Strip lower 3 bits of each color and determine if lighting should be used:
531                                 if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
532                                         driver_idx |= Lighting;
533                                 PS driver = gpuSpriteSpanDrivers[driver_idx];
534                                 gpuDrawS(packet, driver);
535                                 gpu_unai.fb_dirty = true;
536                                 DO_LOG(("gpuDrawS(0x%x)\n",PRIM));
537                         }
538                 } break;
539
540                 case 0x78:
541                 case 0x79:
542                 case 0x7A:
543                 case 0x7B: {          // Monochrome rectangle (16x16)
544                         if (!gpu_unai.frameskip.skipGPU)
545                         {
546                                 NULL_GPU();
547                                 gpu_unai.PacketBuffer.U4[2] = 0x00100010;
548                                 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
549                                 gpuDrawT(packet, driver);
550                                 gpu_unai.fb_dirty = true;
551                                 DO_LOG(("gpuDrawT(0x%x)\n",PRIM));
552                         }
553                 } break;
554
555                 case 0x7C:
556                 case 0x7D:
557                         #ifdef __arm__
558                         /* Notaz 4bit sprites optimization */
559                         if ((!gpu_unai.frameskip.skipGPU) && (!(gpu_unai.GPU_GP1&0x180)) && (!(gpu_unai.Masking|gpu_unai.PixelMSB)))
560                         {
561                                 gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
562                                 gpuDrawS16(packet);
563                                 gpu_unai.fb_dirty = true;
564                                 break;
565                         }
566                         #endif
567                 case 0x7E:
568                 case 0x7F: {          // Textured rectangle (16x16)
569                         if (!gpu_unai.frameskip.skipGPU)
570                         {
571                                 NULL_GPU();
572                                 gpu_unai.PacketBuffer.U4[3] = 0x00100010;
573                                 gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
574                                 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
575
576                                 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
577                                 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
578                                 // Strip lower 3 bits of each color and determine if lighting should be used:
579                                 if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
580                                         driver_idx |= Lighting;
581                                 PS driver = gpuSpriteSpanDrivers[driver_idx];
582                                 gpuDrawS(packet, driver);
583                                 gpu_unai.fb_dirty = true;
584                                 DO_LOG(("gpuDrawS(0x%x)\n",PRIM));
585                         }
586                 } break;
587
588                 case 0x80:          //  vid -> vid
589                         gpuMoveImage(packet);   //  prim handles updateLace && skip
590                         if ((!gpu_unai.frameskip.skipCount) && (gpu_unai.DisplayArea[3] == 480)) // Tekken 3 hack
591                         {
592                                 if (!gpu_unai.frameskip.skipGPU) gpu_unai.fb_dirty = true;
593                         }
594                         else
595                         {
596                                 gpu_unai.fb_dirty = true;
597                         }
598                         DO_LOG(("gpuMoveImage(0x%x)\n",PRIM));
599                         break;
600                 case 0xA0:          //  sys ->vid
601                         gpuLoadImage(packet);   //  prim handles updateLace && skip
602                         DO_LOG(("gpuLoadImage(0x%x)\n",PRIM));
603                         break;
604                 case 0xC0:          //  vid -> sys
605                         gpuStoreImage(packet);  //  prim handles updateLace && skip
606                         DO_LOG(("gpuStoreImage(0x%x)\n",PRIM));
607                         break;
608                 case 0xE1 ... 0xE6: { // Draw settings
609                         gpuGP0Cmd_0xEx(gpu_unai, gpu_unai.PacketBuffer.U4[0]);
610                 } break;
611         }
612 }
613 #endif //!USE_GPULIB
614 ///////////////////////////////////////////////////////////////////////////////
615 // End of code specific to non-gpulib standalone version of gpu_unai
616 ///////////////////////////////////////////////////////////////////////////////