Previous 199869 Revisions Next

r36189 Monday 2nd March, 2015 at 17:42:36 UTC by David Haywood
split the hng64 code into more files, easier to work with, also modernize a bit more (nw)
[src/mame]mame.mak
[src/mame/drivers]hng64.c
[src/mame/includes]hng64.h
[src/mame/video]hng64.c hng64_3d.c* hng64_sprite.c*

trunk/src/mame/drivers/hng64.c
r244700r244701
812812}
813813
814814
815// Hardware calls these '3d buffers'
816//   They're only read during the startup check of fatfurwa.  Z-buffer memory?  Front buffer, back buffer?
817//   They're definitely mirrored in the startup test.  Elsemi says:
818//   <ElSemi> 30100000-3011ffff is framebuffer A0
819//   <ElSemi> 30120000-3013ffff is framebuffer A1
820//   <ElSemi> 30140000-3015ffff is ZBuffer A
821READ32_MEMBER(hng64_state::hng64_3d_1_r)
822{
823   return m_3d_1[offset];
824}
825
826WRITE32_MEMBER(hng64_state::hng64_3d_1_w)
827{
828   COMBINE_DATA (&m_3d_1[offset]);
829}
830
831READ32_MEMBER(hng64_state::hng64_3d_2_r)
832{
833   return m_3d_2[offset];
834}
835
836WRITE32_MEMBER(hng64_state::hng64_3d_2_w)
837{
838   COMBINE_DATA (&m_3d_2[offset]);
839}
840
841// The 3d 'display list'
842WRITE32_MEMBER(hng64_state::dl_w)
843{
844   UINT32 *hng64_dl = m_dl;
845   //UINT16 packet3d[16];
846
847   COMBINE_DATA(&hng64_dl[offset]);
848
849#if 0
850   if (offset == 0x08 || offset == 0x7f || // Special buggers.
851      offset == 0x10 || offset == 0x18 ||
852      offset == 0x20 || offset == 0x28 ||
853      offset == 0x30 || offset == 0x38 ||
854      offset == 0x40 || offset == 0x48 ||
855      offset == 0x50 || offset == 0x58 ||
856      offset == 0x60 || offset == 0x68 ||
857      offset == 0x70 || offset == 0x78)
858   {
859      // Create a 3d packet
860      UINT16 packetStart = offset - 0x08;
861      if (offset == 0x7f) packetStart += 1;
862
863      for (i = 0; i < 0x08; i++)
864      {
865         packet3d[i*2+0] = (hng64_dl[packetStart+i] & 0xffff0000) >> 16;
866         packet3d[i*2+1] = (hng64_dl[packetStart+i] & 0x0000ffff);
867      }
868
869      // Send it off to the 3d subsystem.
870      hng64_command3d( packet3d);
871   }
872#endif
873}
874
875#if 0
876READ32_MEMBER(hng64_state::dl_r)
877{
878   //osd_printf_debug("dl R (%08x) : %x %x\n", space.device().safe_pc(), offset, hng64_dl[offset]);
879   //usrintf_showmessage("dl R (%08x) : %x %x", space.device().safe_pc(), offset, hng64_dl[offset]);
880   return hng64_dl[offset];
881}
882#endif
883
884TIMER_CALLBACK_MEMBER(hng64_state::hng64_3dfifo_processed )
885{
886// ...
887   m_set_irq(0x0008);
888}
889
890/* TODO: different param for both Samurai games, less FIFO to process? */
891WRITE32_MEMBER(hng64_state::dl_upload_w)
892{
893   // this handles 3d to fb upload
894   UINT16 packet3d[16];
895//   printf("dl_upload_w %08x %08x\n", data, mem_mask);
896
897
898   for(int packetStart=0;packetStart<0x200/4;packetStart+=8)
899   {
900      // Create a 3d packet
901      //UINT16 packetStart = offset - 0x08;
902      //if (offset == 0x7f) packetStart += 1;
903
904      for (int i = 0; i < 0x08; i++)
905      {
906         packet3d[i*2+0] = (m_dl[packetStart+i] & 0xffff0000) >> 16;
907         packet3d[i*2+1] = (m_dl[packetStart+i] & 0x0000ffff);
908      }
909
910      // Send it off to the 3d subsystem.
911      hng64_command3d( packet3d);
912   }
913
914   machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(0x200*8), timer_expired_delegate(FUNC(hng64_state::hng64_3dfifo_processed),this));
915}
916
917/* Note: Samurai Shodown games never calls bit 1, so it can't be framebuffer clear. It also calls bit 3 at start-up, meaning unknown */
918WRITE32_MEMBER(hng64_state::dl_control_w) // This handles framebuffers
919{
920//   printf("dl_control_w %08x %08x\n", data, mem_mask);
921
922   //if(data & 2) // swap buffers
923   //{
924   //  clear3d();
925   //}
926
927//  printf("%02x\n",data);
928
929//  if(data & 1) // process DMA from 3d FIFO to framebuffer
930
931//  if(data & 4) // reset buffer count
932}
933
934#ifdef UNUSED_FUNCTION
935WRITE32_MEMBER(hng64_state::activate_3d_buffer)
936{
937   COMBINE_DATA (&active_3d_buffer[offset]);
938   osd_printf_debug("COMBINED %d\n", active_3d_buffer[offset]);
939}
940#endif
941
942815// Transition Control memory.
943816WRITE32_MEMBER(hng64_state::tcram_w)
944817{
r244700r244701
12101083   AM_RANGE(0x20190000, 0x20190037) AM_RAM_WRITE(hng64_vregs_w) AM_SHARE("videoregs")
12111084   AM_RANGE(0x20200000, 0x20203fff) AM_RAM_WRITE(hng64_pal_w) AM_SHARE("paletteram")
12121085   AM_RANGE(0x20208000, 0x2020805f) AM_READWRITE(tcram_r, tcram_w) AM_SHARE("tcram")   // Transition Control
1213   AM_RANGE(0x20300000, 0x203001ff) AM_RAM_WRITE(dl_w) AM_SHARE("dl") // 3d Display List
1086   AM_RANGE(0x20300000, 0x203001ff) AM_WRITE16(dl_w,0xffffffff) // 3d Display List
12141087   AM_RANGE(0x20300200, 0x20300203) AM_WRITE(dl_upload_w)  // 3d Display List Upload
12151088   AM_RANGE(0x20300214, 0x20300217) AM_WRITE(dl_control_w)
12161089   AM_RANGE(0x20300218, 0x2030021b) AM_READ(unk_vreg_r)
trunk/src/mame/includes/hng64.h
r244700r244701
3030};
3131
3232
33///////////////
34// 3d Engine //
35///////////////
3336
37struct polyVert
38{
39   float worldCoords[4];   // World space coordinates (X Y Z 1.0)
40
41   float texCoords[4];     // Texture coordinates (U V 0 1.0) -> OpenGL style...
42
43   float normal[4];        // Normal (X Y Z 1.0)
44   float clipCoords[4];    // Homogeneous screen space coordinates (X Y Z W)
45
46   float light[3];         // The intensity of the illumination at this point
47};
48
49struct polygon
50{
51   int n;                      // Number of sides
52   struct polyVert vert[10];   // Vertices (maximum number per polygon is 10 -> 3+6)
53
54   float faceNormal[4];        // Normal of the face overall - for calculating visibility and flat-shading...
55   int visible;                // Polygon visibility in scene
56
57   UINT8 texIndex;             // Which texture to draw from (0x00-0x0f)
58   UINT8 texType;              // How to index into the texture
59   UINT8 texPageSmall;         // Does this polygon use 'small' texture pages?
60   UINT8 texPageHorizOffset;   // If it does use small texture pages, how far is this page horizontally offset?
61   UINT8 texPageVertOffset;    // If it does use small texture pages, how far is this page vertically offset?
62
63   UINT32 palOffset;           // The base offset where this object's palette starts.
64   UINT32 palPageSize;         // The size of the palette page that is being pointed to.
65
66   UINT32 debugColor;          // Will go away someday.  Used to explicitly color polygons for debugging.
67};
68
69
70
3471///////////////////////
3572// polygon rendering //
3673///////////////////////
r244700r244701
4784   int debugColor;
4885};
4986
87// Refer to the clipping planes as numbers
88#define HNG64_LEFT   0
89#define HNG64_RIGHT  1
90#define HNG64_TOP    2
91#define HNG64_BOTTOM 3
92#define HNG64_NEAR   4
93#define HNG64_FAR    5
94
95
96
5097class hng64_state : public driver_device
5198{
5299public:
r244700r244701
66113      m_videoram(*this, "videoram"),
67114      m_videoregs(*this, "videoregs"),
68115      m_tcram(*this, "tcram"),
69      m_dl(*this, "dl"),
70116      m_3dregs(*this, "3dregs"),
71117      m_3d_1(*this, "3d_1"),
72118      m_3d_2(*this, "3d_2"),
r244700r244701
93139   required_shared_ptr<UINT32> m_videoregs;
94140   required_shared_ptr<UINT32> m_tcram;
95141   /* 3D stuff */
96   required_shared_ptr<UINT32> m_dl;
142   UINT16* m_dl;
143
97144   required_shared_ptr<UINT32> m_3dregs;
98145   required_shared_ptr<UINT32> m_3d_1;
99146   required_shared_ptr<UINT32> m_3d_2;
r244700r244701
153200   UINT32 m_old_animbits;
154201   UINT16 m_old_tileflags[4];
155202
156   UINT32 m_dls[2][0x81];
157
158203   // 3d State
159204   int m_paletteState3d;
160205   float m_projectionMatrix[16];
r244700r244701
184229   DECLARE_READ32_MEMBER(hng64_3d_2_r);
185230   DECLARE_WRITE32_MEMBER(hng64_3d_1_w);
186231   DECLARE_WRITE32_MEMBER(hng64_3d_2_w);
187   DECLARE_WRITE32_MEMBER(dl_w);
188   DECLARE_READ32_MEMBER(dl_r);
232   DECLARE_WRITE16_MEMBER(dl_w);
233   //DECLARE_READ32_MEMBER(dl_r);
189234   DECLARE_WRITE32_MEMBER(dl_control_w);
190235   DECLARE_WRITE32_MEMBER(dl_upload_w);
191236   DECLARE_WRITE32_MEMBER(tcram_w);
r244700r244701
294339
295340   void hng64_patch_bios_region(int region);
296341
342   void printPacket(const UINT16* packet, int hex);
343   void matmul4(float *product, const float *a, const float *b);
344   void vecmatmul4(float *product, const float *a, const float *b);
345   float vecDotProduct(const float *a, const float *b);
346   void setIdentity(float *matrix);
347   float uToF(UINT16 input);
348   void normalize(float* x);
349   int Inside(struct polyVert *v, int plane);
350   void Intersect(struct polyVert *input0, struct polyVert *input1, struct polyVert *output, int plane);
351   void performFrustumClip(struct polygon *p);
352   UINT8 *m_texturerom;
353   UINT16* m_vertsrom;
354   int m_vertsrom_size;
355
297356};
298357
trunk/src/mame/mame.mak
r244700r244701
18271827$(MAMEOBJ)/snk.a: \
18281828   $(DRIVERS)/bbusters.o $(VIDEO)/bbusters.o \
18291829   $(DRIVERS)/dmndrby.o \
1830   $(DRIVERS)/hng64.o $(VIDEO)/hng64.o \
1830   $(DRIVERS)/hng64.o $(VIDEO)/hng64.o $(VIDEO)/hng64_3d.o $(VIDEO)/hng64_sprite.o \
18311831   $(DRIVERS)/lasso.o $(VIDEO)/lasso.o \
18321832   $(DRIVERS)/mainsnk.o $(VIDEO)/mainsnk.o \
18331833   $(DRIVERS)/munchmo.o $(VIDEO)/munchmo.o \
trunk/src/mame/video/hng64.c
r244700r244701
22#include "drawgfxm.h"
33#include "includes/hng64.h"
44
5#define MAKE_MAME_REEEEAAALLLL_SLOW 0
5#define BLEND_TEST 0
66
77
88
99
10void hng64_state::hng64_mark_all_tiles_dirty( int tilemap )
11{
12   m_tilemap[tilemap].m_tilemap_8x8->mark_all_dirty();
13   m_tilemap[tilemap].m_tilemap_16x16->mark_all_dirty();
14   m_tilemap[tilemap].m_tilemap_16x16_alt->mark_all_dirty();
15}
1610
17void hng64_state::hng64_mark_tile_dirty( int tilemap, int tile_index )
18{
19   m_tilemap[tilemap].m_tilemap_8x8->mark_tile_dirty(tile_index);
20   m_tilemap[tilemap].m_tilemap_16x16->mark_tile_dirty(tile_index);
21   m_tilemap[tilemap].m_tilemap_16x16_alt->mark_tile_dirty(tile_index);
22}
2311
24
25/*
26 * Sprite Format
27 * ------------------
28 *
29 * UINT32 | Bits                                    | Use
30 *        | 3322 2222 2222 1111 1111 11             |
31 * -------+-1098-7654-3210-9876-5432-1098-7654-3210-+----------------
32 *   0    | yyyy yyyy yyyy yyyy xxxx xxxx xxxx xxxx | x/y position
33 *   1    | YYYY YYYY YYYY YYYY XXXX XXXX XXXX XXXX | x/y zoom (*)
34 *   2    | ---- -zzz zzzz zzzz ---- ---I cccc CCCC | Z-buffer value, 'Inline' chain flag, x/y chain
35 *   3    | ---- ---- pppp pppp ---- ---- ---- ---- | palette entry
36 *   4    | mmmm -?fF a??? tttt tttt tttt tttt tttt | mosaic factor, unknown (**) , flip bits, additive blending, unknown (***), tile number
37 *   5    | ---- ---- ---- ---- ---- ---- ---- ---- | not used ??
38 *   6    | ---- ---- ---- ---- ---- ---- ---- ---- | not used ??
39 *   7    | ---- ---- ---- ---- ---- ---- ---- ---- | not used ??
40 *
41 * (*) Fatal Fury WA standard elements are 0x1000-0x1000, all the other games sets 0x100-0x100, related to the bit 27 of sprite regs 0?
42 * (**) setted by black squares in ranking screen in Samurai Shodown 64 1, sprite disable?
43 * (***) bit 22 is setted on some Fatal Fury WA snow (not all of them), bit 21 is setted on Xrally how to play elements in attract mode
44 *
45 * Sprite Global Registers
46 * -----------------------
47 *
48 * UINT32 | Bits                                    | Use
49 *        | 3322 2222 2222 1111 1111 11             |
50 * -------+-1098-7654-3210-9876-5432-1098-7654-3210-+----------------
51 *   0    | ---- z--- b--- ---- ---- ---- ---- ---- | zooming mode, bpp select
52 *   1    | yyyy yyyy yyyy yyyy xxxx xxxx xxxx xxxx | global sprite offset (ss64 rankings in attract)
53 *   2    | ---- ---- ---- ---- ---- ---- ---- ---- |
54 *   3    | ---- ---- ---- ---- ---- ---- ---- ---- |
55 *   4    | ---- ---- ---- ---- ---- ---- ---- ---- |
56 * (anything else is unknown at the current time)
57 * Notes:
58 * [0]
59 * 0xf0000000 setted in both Samurai Shodown
60 * 0x00060000 always setted in all the games
61 * 0x00010000 setted in POST, sprite disable?
62 * [4]
63 * 0x0e0 in Samurai Shodown/Xrally games, 0x1c0 in all the others, zooming factor?
64 */
65
66void hng64_state::draw_sprites(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
67{
68   gfx_element *gfx;
69   UINT32 *source = m_spriteram;
70   UINT32 *finish = m_spriteram + 0xc000/4;
71
72   // global offsets in sprite regs
73   int spriteoffsx = (m_spriteregs[1]>>0)&0xffff;
74   int spriteoffsy = (m_spriteregs[1]>>16)&0xffff;
75
76#if 0
77   for (int iii = 0; iii < 0x0f; iii++)
78      osd_printf_debug("%.8x ", m_videoregs[iii]);
79   osd_printf_debug("\n");
80#endif
81
82   while( source<finish )
83   {
84      int tileno,chainx,chainy,xflip;
85      int pal,xinc,yinc,yflip;
86      UINT16 xpos, ypos;
87      int xdrw,ydrw;
88      int chaini;
89      int zbuf;
90      UINT32 zoomx,zoomy;
91      float foomX, foomY;
92      int blend;
93      int disable;
94
95
96
97      ypos = (source[0]&0xffff0000)>>16;
98      xpos = (source[0]&0x0000ffff)>>0;
99      xpos += (spriteoffsx);
100      ypos += (spriteoffsy);
101
102      tileno= (source[4]&0x0007ffff);
103      blend=  (source[4]&0x00800000);
104      yflip=  (source[4]&0x01000000)>>24;
105      xflip=  (source[4]&0x02000000)>>25;
106      disable=(source[4]&0x04000000)>>26; // ss64 rankings?
107
108      pal =(source[3]&0x00ff0000)>>16;
109
110      chainy=(source[2]&0x0000000f);
111      chainx=(source[2]&0x000000f0)>>4;
112      chaini=(source[2]&0x00000100);
113      zbuf = (source[2]&0x07ff0000)>>16; //?
114
115      zoomy = (source[1]&0xffff0000)>>16;
116      zoomx = (source[1]&0x0000ffff)>>0;
117
118      #if 1
119      if(zbuf == 0x7ff) //temp kludge to avoid garbage on screen
120      {
121         source+=8;
122         continue;
123      }
124      #endif
125      if(disable)
126      {
127         source+=8;
128         continue;
129      }
130
131#if 0
132      if (!(source[4] == 0x00000000 || source[4] == 0x000000aa))
133         osd_printf_debug("unknown : %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x \n", source[0], source[1], source[2], source[3],
134            source[4], source[5], source[6], source[7]);
135#endif
136
137      /* Calculate the zoom */
138      {
139         int zoom_factor;
140
141         /* FIXME: regular zoom mode has precision bugs, can be easily seen in Samurai Shodown 64 intro */
142         zoom_factor = (m_spriteregs[0] & 0x08000000) ? 0x1000 : 0x100;
143         if(!zoomx) zoomx=zoom_factor;
144         if(!zoomy) zoomy=zoom_factor;
145
146         /* First, prevent any possible divide by zero errors */
147         foomX = (float)(zoom_factor) / (float)zoomx;
148         foomY = (float)(zoom_factor) / (float)zoomy;
149
150         zoomx = ((int)foomX) << 16;
151         zoomy = ((int)foomY) << 16;
152
153         zoomx += (int)((foomX - floor(foomX)) * (float)0x10000);
154         zoomy += (int)((foomY - floor(foomY)) * (float)0x10000);
155      }
156
157      if (m_spriteregs[0] & 0x00800000) //bpp switch
158      {
159         gfx= m_gfxdecode->gfx(4);
160      }
161      else
162      {
163         gfx= m_gfxdecode->gfx(5);
164         tileno>>=1;
165         pal&=0xf;
166      }
167
168      // Accommodate for chaining and flipping
169      if(xflip)
170      {
171         xinc=-(int)(16.0f*foomX);
172         xpos-=xinc*chainx;
173      }
174      else
175      {
176         xinc=(int)(16.0f*foomX);
177      }
178
179      if(yflip)
180      {
181         yinc=-(int)(16.0f*foomY);
182         ypos-=yinc*chainy;
183      }
184      else
185      {
186         yinc=(int)(16.0f*foomY);
187      }
188
189#if 0
190      if (((source[2) & 0xffff0000) >> 16) == 0x0001)
191      {
192         popmessage("T %.8x %.8x %.8x %.8x %.8x", source[0], source[1], source[2], source[3], source[4]);
193         //popmessage("T %.8x %.8x %.8x %.8x %.8x", source[0], source[1], source[2], source[3], source[4]);
194      }
195#endif
196
197      for(ydrw=0;ydrw<=chainy;ydrw++)
198      {
199         for(xdrw=0;xdrw<=chainx;xdrw++)
200         {
201            INT16 drawx = xpos+(xinc*xdrw);
202            INT16 drawy = ypos+(yinc*ydrw);
203
204            // 0x3ff (0x200 sign bit) based on sams64_2 char select
205            drawx &= 0x3ff;
206            drawy &= 0x3ff;
207
208            if (drawx&0x0200)drawx-=0x400;
209            if (drawy&0x0200)drawy-=0x400;
210
211            if (!chaini)
212            {
213               if (!blend) gfx->prio_zoom_transpen(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0);
214               else gfx->prio_zoom_transpen_additive(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0);
215               tileno++;
216            }
217            else // inline chain mode, used by ss64
218            {
219               tileno=(source[4]&0x0007ffff);
220               pal =(source[3]&0x00ff0000)>>16;
221
222               if (m_spriteregs[0] & 0x00800000) //bpp switch
223               {
224                  gfx= m_gfxdecode->gfx(4);
225               }
226               else
227               {
228                  gfx= m_gfxdecode->gfx(5);
229                  tileno>>=1;
230                  pal&=0xf;
231               }
232
233               if (!blend) gfx->prio_zoom_transpen(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0);
234               else gfx->prio_zoom_transpen_additive(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0);
235               source +=8;
236            }
237
238         }
239      }
240
241      if (!chaini) source +=8;
242   }
243}
244
245
24612/* Transition Control Video Registers
24713 * ----------------------------------
24814 *
r244700r244701
378144   }
379145}
380146
147
148
149void hng64_state::hng64_mark_all_tiles_dirty( int tilemap )
150{
151   m_tilemap[tilemap].m_tilemap_8x8->mark_all_dirty();
152   m_tilemap[tilemap].m_tilemap_16x16->mark_all_dirty();
153   m_tilemap[tilemap].m_tilemap_16x16_alt->mark_all_dirty();
154}
155
156void hng64_state::hng64_mark_tile_dirty( int tilemap, int tile_index )
157{
158   m_tilemap[tilemap].m_tilemap_8x8->mark_tile_dirty(tile_index);
159   m_tilemap[tilemap].m_tilemap_16x16->mark_tile_dirty(tile_index);
160   m_tilemap[tilemap].m_tilemap_16x16_alt->mark_tile_dirty(tile_index);
161}
162
163
381164// make this a function!
382165// pppppppp ff--atttt tttttttt tttttttt
383166#define HNG64_GET_TILE_INFO                                                    \
r244700r244701
1022805
1023806
1024807         /* manual copy = slooow */
1025         if (MAKE_MAME_REEEEAAALLLL_SLOW)
808         if (BLEND_TEST)
1026809         {
1027810            bitmap_ind16 &bm = tilemap->pixmap();
1028811            int bmheight = bm.height();
r244700r244701
1118901         yinc = (ymiddle - ytopleft) / 512;
1119902
1120903         /* manual copy = slooow */
1121         if (MAKE_MAME_REEEEAAALLLL_SLOW)
904         if (BLEND_TEST)
1122905         {
1123906            bitmap_ind16 &bm = tilemap->pixmap();
1124907            int bmheight = bm.height();
r244700r244701
14601243   // 3d Buffer Allocation
14611244   m_depthBuffer3d = auto_alloc_array(machine(), float,  (visarea.max_x + 1)*(visarea.max_y + 1));
14621245   m_colorBuffer3d = auto_alloc_array(machine(), UINT32, (visarea.max_x + 1)*(visarea.max_y + 1));
1463}
14641246
14651247
1466///////////////
1467// 3d Engine //
1468///////////////
1248   m_dl = auto_alloc_array(machine(), UINT16, 0x200/2);
14691249
1470struct polyVert
1471{
1472   float worldCoords[4];   // World space coordinates (X Y Z 1.0)
1473
1474   float texCoords[4];     // Texture coordinates (U V 0 1.0) -> OpenGL style...
1475
1476   float normal[4];        // Normal (X Y Z 1.0)
1477   float clipCoords[4];    // Homogeneous screen space coordinates (X Y Z W)
1478
1479   float light[3];         // The intensity of the illumination at this point
1480};
1481
1482struct polygon
1483{
1484   int n;                      // Number of sides
1485   struct polyVert vert[10];   // Vertices (maximum number per polygon is 10 -> 3+6)
1486
1487   float faceNormal[4];        // Normal of the face overall - for calculating visibility and flat-shading...
1488   int visible;                // Polygon visibility in scene
1489
1490   UINT8 texIndex;             // Which texture to draw from (0x00-0x0f)
1491   UINT8 texType;              // How to index into the texture
1492   UINT8 texPageSmall;         // Does this polygon use 'small' texture pages?
1493   UINT8 texPageHorizOffset;   // If it does use small texture pages, how far is this page horizontally offset?
1494   UINT8 texPageVertOffset;    // If it does use small texture pages, how far is this page vertically offset?
1495
1496   UINT32 palOffset;           // The base offset where this object's palette starts.
1497   UINT32 palPageSize;         // The size of the palette page that is being pointed to.
1498
1499   UINT32 debugColor;          // Will go away someday.  Used to explicitly color polygons for debugging.
1500};
1501
1502static void setIdentity(float *matrix);
1503static void matmul4(float *product, const float *a, const float *b);
1504static void vecmatmul4(float *product, const float *a, const float *b);
1505static float vecDotProduct(const float *a, const float *b);
1506static void normalize(float* x);
1507static void performFrustumClip(struct polygon *p);
1508static float uToF(UINT16 input);
1509
1510
1511////////////////////
1512// 3d 'Functions' //
1513////////////////////
1514
1515static void printPacket(const UINT16* packet, int hex)
1516{
1517   if (hex)
1518   {
1519      printf("Packet : %04x %04x  2:%04x %04x  4:%04x %04x  6:%04x %04x  8:%04x %04x  10:%04x %04x  12:%04x %04x  14:%04x %04x\n",
1520            packet[0],  packet[1],
1521            packet[2],  packet[3],
1522            packet[4],  packet[5],
1523            packet[6],  packet[7],
1524            packet[8],  packet[9],
1525            packet[10], packet[11],
1526            packet[12], packet[13],
1527            packet[14], packet[15]);
1528   }
1529   else
1530   {
1531      printf("Packet : %04x %3.4f  2:%3.4f %3.4f  4:%3.4f %3.4f  6:%3.4f %3.4f  8:%3.4f %3.4f  10:%3.4f %3.4f  12:%3.4f %3.4f  14:%3.4f %3.4f\n",
1532            packet[0],            uToF(packet[1] )*128,
1533            uToF(packet[2] )*128, uToF(packet[3] )*128,
1534            uToF(packet[4] )*128, uToF(packet[5] )*128,
1535            uToF(packet[6] )*128, uToF(packet[7] )*128,
1536            uToF(packet[8] )*128, uToF(packet[9] )*128,
1537            uToF(packet[10])*128, uToF(packet[11])*128,
1538            uToF(packet[12])*128, uToF(packet[13])*128,
1539            uToF(packet[14])*128, uToF(packet[15])*128);
1540   }
1250   m_texturerom = memregion("textures")->base();
1251   m_vertsrom = (UINT16*)memregion("verts")->base();
1252   m_vertsrom_size = memregion("verts")->bytes();
15411253}
15421254
1543// Operation 0001
1544// Camera transformation.
1545void hng64_state::setCameraTransformation(const UINT16* packet)
1546{
1547   float *cameraMatrix = m_cameraMatrix;
1548
1549   /*//////////////
1550   // PACKET FORMAT
1551   // [0]  - 0001 ... ID
1552   // [1]  - xxxx ... Extrinsic camera matrix
1553   // [2]  - xxxx ... Extrinsic camera matrix
1554   // [3]  - xxxx ... Extrinsic camera matrix
1555   // [4]  - xxxx ... Extrinsic camera matrix
1556   // [5]  - xxxx ... Extrinsic camera matrix
1557   // [6]  - xxxx ... Extrinsic camera matrix
1558   // [7]  - xxxx ... Extrinsic camera matrix
1559   // [8]  - xxxx ... Extrinsic camera matrix
1560   // [9]  - xxxx ... Extrinsic camera matrix
1561   // [10] - xxxx ... Extrinsic camera matrix
1562   // [11] - xxxx ... Extrinsic camera matrix
1563   // [12] - xxxx ... Extrinsic camera matrix
1564   // [13] - ???? ... ? Flips per-frame during fatfurwa 'HNG64'
1565   // [14] - ???? ... ? Could be some floating-point values during buriki 'door run'
1566   // [15] - ???? ... ? Same as 13 & 14
1567   ////////////*/
1568   // CAMERA TRANSFORMATION MATRIX
1569   cameraMatrix[0]  = uToF(packet[1]);
1570   cameraMatrix[4]  = uToF(packet[2]);
1571   cameraMatrix[8]  = uToF(packet[3]);
1572   cameraMatrix[3]  = 0.0f;
1573
1574   cameraMatrix[1]  = uToF(packet[4]);
1575   cameraMatrix[5]  = uToF(packet[5]);
1576   cameraMatrix[9]  = uToF(packet[6]);
1577   cameraMatrix[7]  = 0.0f;
1578
1579   cameraMatrix[2]  = uToF(packet[7]);
1580   cameraMatrix[6]  = uToF(packet[8]);
1581   cameraMatrix[10] = uToF(packet[9]);
1582   cameraMatrix[11] = 0.0f;
1583
1584   cameraMatrix[12] = uToF(packet[10]);
1585   cameraMatrix[13] = uToF(packet[11]);
1586   cameraMatrix[14] = uToF(packet[12]);
1587   cameraMatrix[15] = 1.0f;
1588}
1589
1590// Operation 0010
1591// Lighting information
1592void hng64_state::setLighting(const UINT16* packet)
1593{
1594   float *lightVector = m_lightVector;
1595
1596   /*//////////////
1597   // PACKET FORMAT
1598   // [0]  - 0010 ... ID
1599   // [1]  - ???? ... ? Always zero
1600   // [2]  - ???? ... ? Always zero
1601   // [3]  - xxxx ... X light vector direction
1602   // [4]  - xxxx ... Y light vector direction
1603   // [5]  - xxxx ... Z light vector direction
1604   // [6]  - ???? ... ? Seems to be another light vector ?
1605   // [7]  - ???? ... ? Seems to be another light vector ?
1606   // [8]  - ???? ... ? Seems to be another light vector ?
1607   // [9]  - xxxx ... Strength according to sams64_2 [0000,01ff]
1608   // [10] - ???? ... ? Used in fatfurwa
1609   // [11] - ???? ... ? Used in fatfurwa
1610   // [12] - ???? ... ? Used in fatfurwa
1611   // [13] - ???? ... ? Used in fatfurwa
1612   // [14] - ???? ... ? Used in fatfurwa
1613   // [15] - ???? ... ? Used in fatfurwa
1614   ////////////*/
1615   if (packet[1] != 0x0000) printf("ZOMG!  packet[1] in setLighting function is non-zero!\n");
1616   if (packet[2] != 0x0000) printf("ZOMG!  packet[2] in setLighting function is non-zero!\n");
1617
1618   lightVector[0] = uToF(packet[3]);
1619   lightVector[1] = uToF(packet[4]);
1620   lightVector[2] = uToF(packet[5]);
1621   m_lightStrength = uToF(packet[9]);
1622}
1623
1624// Operation 0011
1625// Palette / Model flags?
1626void hng64_state::set3dFlags(const UINT16* packet)
1627{
1628   /*//////////////
1629   // PACKET FORMAT
1630   // [0]  - 0011 ... ID
1631   // [1]  - ???? ...
1632   // [2]  - ???? ...
1633   // [3]  - ???? ...
1634   // [4]  - ???? ...
1635   // [5]  - ???? ...
1636   // [6]  - ???? ...
1637   // [7]  - ???? ...
1638   // [8]  - xx?? ... Palette offset & ??
1639   // [9]  - ???? ... ? Very much used - seem to bounce around when characters are on screen
1640   // [10] - ???? ... ? ''  ''
1641   // [11] - ???? ... ? ''  ''
1642   // [12] - ???? ... ? ''  ''
1643   // [13] - ???? ... ? ''  ''
1644   // [14] - ???? ... ? ''  ''
1645   // [15] - ???? ... ? ''  ''
1646   ////////////*/
1647   m_paletteState3d = (packet[8] & 0xff00) >> 8;
1648}
1649
1650// Operation 0012
1651// Projection Matrix.
1652void hng64_state::setCameraProjectionMatrix(const UINT16* packet)
1653{
1654   float *projectionMatrix = m_projectionMatrix;
1655
1656   /*//////////////
1657   // PACKET FORMAT
1658   // [0]  - 0012 ... ID
1659   // [1]  - ???? ... ? Contains a value in buriki's 'how to play' - probably a projection window/offset.
1660   // [2]  - ???? ... ? Contains a value in buriki's 'how to play' - probably a projection window/offset.
1661   // [3]  - ???? ... ? Contains a value
1662   // [4]  - xxxx ... Camera projection near scale
1663   // [5]  - xxxx ... Camera projection near height(?)
1664   // [6]  - xxxx ... Camera projection near width(?)
1665   // [7]  - xxxx ... Camera projection far scale
1666   // [8]  - xxxx ... Camera projection far height(?)
1667   // [9]  - xxxx ... Camera projection far width(?)
1668   // [10] - xxxx ... Camera projection right
1669   // [11] - xxxx ... Camera projection left
1670   // [12] - xxxx ... Camera projection top
1671   // [13] - xxxx ... Camera projection bottom
1672   // [14] - ???? ... ? Gets data during buriki door-run
1673   // [15] - ???? ... ? Gets data during buriki door-run
1674   ////////////*/
1675
1676   // Heisted from GLFrustum - 6 parameters...
1677   float left, right, top, bottom, near_, far_;
1678
1679   left    = uToF(packet[11]);
1680   right   = uToF(packet[10]);
1681   top     = uToF(packet[12]);
1682   bottom  = uToF(packet[13]);
1683   near_   = uToF(packet[6]) + (uToF(packet[6]) * uToF(packet[4]));
1684   far_    = uToF(packet[9]) + (uToF(packet[9]) * uToF(packet[7]));
1685   // (note are likely not 100% correct - I'm not using one of the parameters)
1686
1687   projectionMatrix[0]  = (2.0f*near_)/(right-left);
1688   projectionMatrix[1]  = 0.0f;
1689   projectionMatrix[2]  = 0.0f;
1690   projectionMatrix[3]  = 0.0f;
1691
1692   projectionMatrix[4]  = 0.0f;
1693   projectionMatrix[5]  = (2.0f*near_)/(top-bottom);
1694   projectionMatrix[6]  = 0.0f;
1695   projectionMatrix[7]  = 0.0f;
1696
1697   projectionMatrix[8]  = (right+left)/(right-left);
1698   projectionMatrix[9]  = (top+bottom)/(top-bottom);
1699   projectionMatrix[10] = -((far_+near_)/(far_-near_));
1700   projectionMatrix[11] = -1.0f;
1701
1702   projectionMatrix[12] = 0.0f;
1703   projectionMatrix[13] = 0.0f;
1704   projectionMatrix[14] = -((2.0f*far_*near_)/(far_-near_));
1705   projectionMatrix[15] = 0.0f;
1706}
1707
1708// Operation 0100
1709// Polygon rasterization.
1710void hng64_state::recoverPolygonBlock(const UINT16* packet, struct polygon* polys, int* numPolys)
1711{
1712   /*//////////////
1713   // PACKET FORMAT
1714   // [0]  - 0100 ... ID
1715   // [1]  - ?--- ... Flags [?000 = ???
1716   //                        0?00 = ???
1717   //                        00?0 = ???
1718   //                        000? = ???]
1719   // [1]  - -?-- ... Flags [?000 = ???
1720   //                        0?00 = ???
1721   //                        00?0 = ???
1722   //                        000x = Dynamic palette bit]
1723   // [1]  - --?- ... Flags [?000 = ???
1724   //                        0?00 = ???
1725   //                        00?0 = ???
1726   //                        000? = ???]
1727   // [1]  - ---? ... Flags [x000 = Apply lighting bit
1728   //                        0?00 = ???
1729   //                        00?0 = ???
1730   //                        000? = ???]
1731   // [2]  - xxxx ... offset into ROM
1732   // [3]  - xxxx ... offset into ROM
1733   // [4]  - xxxx ... Transformation matrix
1734   // [5]  - xxxx ... Transformation matrix
1735   // [6]  - xxxx ... Transformation matrix
1736   // [7]  - xxxx ... Transformation matrix
1737   // [8]  - xxxx ... Transformation matrix
1738   // [9]  - xxxx ... Transformation matrix
1739   // [10] - xxxx ... Transformation matrix
1740   // [11] - xxxx ... Transformation matrix
1741   // [12] - xxxx ... Transformation matrix
1742   // [13] - xxxx ... Transformation matrix
1743   // [14] - xxxx ... Transformation matrix
1744   // [15] - xxxx ... Transformation matrix
1745   ////////////*/
1746
1747   UINT32 size[4];
1748   UINT32 address[4];
1749   UINT32 megaOffset;
1750   float eyeCoords[4];     // ObjectCoords transformed by the modelViewMatrix
1751//  float clipCoords[4];    // EyeCoords transformed by the projectionMatrix
1752   float ndCoords[4];      // Normalized device coordinates/clipCoordinates (x/w, y/w, z/w)
1753   float windowCoords[4];  // Mapped ndCoordinates to screen space
1754   float cullRay[4];
1755
1756   float objectMatrix[16];
1757   setIdentity(objectMatrix);
1758
1759   struct polygon lastPoly = { 0 };
1760   const rectangle &visarea = m_screen->visible_area();
1761
1762   /////////////////
1763   // HEADER INFO //
1764   /////////////////
1765   // THE OBJECT TRANSFORMATION MATRIX
1766   objectMatrix[8] = uToF(packet[7]);
1767   objectMatrix[4] = uToF(packet[8]);
1768   objectMatrix[0] = uToF(packet[9]);
1769   objectMatrix[3] = 0.0f;
1770
1771   objectMatrix[9] = uToF(packet[10]);
1772   objectMatrix[5] = uToF(packet[11]);
1773   objectMatrix[1] = uToF(packet[12]);
1774   objectMatrix[7] = 0.0f;
1775
1776   objectMatrix[10] = uToF(packet[13]);
1777   objectMatrix[6 ] = uToF(packet[14]);
1778   objectMatrix[2 ] = uToF(packet[15]);
1779   objectMatrix[11] = 0.0f;
1780
1781   objectMatrix[12] = uToF(packet[4]);
1782   objectMatrix[13] = uToF(packet[5]);
1783   objectMatrix[14] = uToF(packet[6]);
1784   objectMatrix[15] = 1.0f;
1785
1786
1787   //////////////////////////////////////////////////////////
1788   // EXTRACT DATA FROM THE ADDRESS POINTED TO IN THE FILE //
1789   //////////////////////////////////////////////////////////
1790   /*//////////////////////////////////////////////
1791   // DIRECTLY-POINTED-TO FORMAT (7 words x 3 ROMs)
1792   // [0]  - lower word of sub-address 1
1793   // [1]  - lower word of sub-address 2
1794   // [2]  - upper word of all sub-addresses
1795   // [3]  - lower word of sub-address 3
1796   // [4]  - lower word of sub-address 4
1797   // [5]  - ???? always 0 ????
1798   // [6]  - number of chunks in sub-address 1 block
1799   // [7]  - number of chunks in sub-address 2 block
1800   // [8]  - ???? always 0 ????
1801   // [9]  - number of chunks in sub-address 3 block
1802   // [10] - number of chunks in sub-address 4 block
1803   // [11] - ? definitely used.
1804   // [12] - ? definitely used.
1805   // [13] - ? definitely used.
1806   // [14] - ? definitely used.
1807   // [15] - ???? always 0 ????
1808   // [16] - ???? always 0 ????
1809   // [17] - ???? always 0 ????
1810   // [18] - ???? always 0 ????
1811   // [19] - ???? always 0 ????
1812   // [20] - ???? always 0 ????
1813   //////////////////////////////////////////////*/
1814
1815   // 3d ROM Offset
1816   UINT16* threeDRoms = (UINT16*)memregion("verts")->base();
1817   UINT32  threeDOffset = (((UINT32)packet[2]) << 16) | ((UINT32)packet[3]);
1818   UINT16* threeDPointer = &threeDRoms[threeDOffset * 3];
1819
1820   if (threeDOffset >= memregion("verts")->bytes())
1821   {
1822      printf("Strange geometry packet: (ignoring)\n");
1823      printPacket(packet, 1);
1824      return;
1825   }
1826
1827#if 0
1828   // Debug - ajg
1829   printf("%08x : ", threeDOffset*3*2);
1830   for (int k = 0; k < 7*3; k++)
1831   {
1832      printf("%04x ", threeDPointer[k]);
1833      if ((k % 3) == 2) printf(" ");
1834   }
1835   printf("\n");
1836#endif
1837
1838   // There are 4 hunks per address.
1839   address[0] = threeDPointer[0];
1840   address[1] = threeDPointer[1];
1841   megaOffset = threeDPointer[2];
1842
1843   address[2] = threeDPointer[3];
1844   address[3] = threeDPointer[4];
1845   if (threeDPointer[5] != 0x0000) printf("ZOMG!  3dPointer[5] is non-zero!\n");
1846
1847   size[0]    = threeDPointer[6];
1848   size[1]    = threeDPointer[7];
1849   if (threeDPointer[8] != 0x0000) printf("ZOMG!  3dPointer[8] is non-zero!\n");
1850
1851   size[2]    = threeDPointer[9];
1852   size[3]    = threeDPointer[10];
1853   /*           ????         [11]; Used. */
1854
1855   /*           ????         [12]; Used. */
1856   /*           ????         [13]; Used. */
1857   /*           ????         [14]; Used. */
1858
1859   if (threeDPointer[15] != 0x0000) printf("ZOMG!  3dPointer[15] is non-zero!\n");
1860   if (threeDPointer[16] != 0x0000) printf("ZOMG!  3dPointer[16] is non-zero!\n");
1861   if (threeDPointer[17] != 0x0000) printf("ZOMG!  3dPointer[17] is non-zero!\n");
1862
1863   if (threeDPointer[18] != 0x0000) printf("ZOMG!  3dPointer[18] is non-zero!\n");
1864   if (threeDPointer[19] != 0x0000) printf("ZOMG!  3dPointer[19] is non-zero!\n");
1865   if (threeDPointer[20] != 0x0000) printf("ZOMG!  3dPointer[20] is non-zero!\n");
1866
1867   /* Concatenate the megaOffset with the addresses */
1868   address[0] |= (megaOffset << 16);
1869   address[1] |= (megaOffset << 16);
1870   address[2] |= (megaOffset << 16);
1871   address[3] |= (megaOffset << 16);
1872
1873   // Debug - ajg
1874   //UINT32 tdColor = 0xff000000;
1875   //if (threeDPointer[14] & 0x0002) tdColor |= 0x00ff0000;
1876   //if (threeDPointer[14] & 0x0001) tdColor |= 0x0000ff00;
1877   //if (threeDPointer[14] & 0x0000) tdColor |= 0x000000ff;
1878
1879   /* For all 4 polygon chunks */
1880   for (int k = 0; k < 4; k++)
1881   {
1882      UINT16* chunkOffset = &threeDRoms[address[k] * 3];
1883      for (int l = 0; l < size[k]; l++)
1884      {
1885         ////////////////////////////////////////////
1886         // GATHER A SINGLE TRIANGLE'S INFORMATION //
1887         ////////////////////////////////////////////
1888         // SINGLE POLY CHUNK FORMAT
1889         // [0] ??-- - ???
1890         // [0] --xx - Chunk type
1891         //
1892         // [1] ?--- - Flags [?000 = ???
1893         //                   0?00 = ???
1894         //                   00?0 = ???
1895         //                   000x = low-res texture flag]
1896         // [1] -x-- - Explicit 0x80 palette index.
1897         // [1] --x- - Explicit 0x08 palette index.
1898         // [1] ---x - Texture page (1024x1024 bytes)
1899         //
1900         // [2] x--- - Texture Flags [x000 = Uses 4x4 sub-texture pages?
1901         //                           0?00 = ??? - differen sub-page size?  SNK logo in RoadEdge.  Always on in bbust2.
1902         //                           00xx = Horizontal sub-texture page index]
1903         // [2] -?-- - ??? - barely visible (thus far) in roadedge
1904         // [2] --x- - Texture Flags [?000 = ???
1905         //                           0xx0 = Vertical sub-texture page index.
1906         //                           000? = ???]
1907         // [2] ---? - ???
1908         //////////////////////////
1909         UINT8 chunkType = chunkOffset[0] & 0x00ff;
1910
1911         // Debug - ajg
1912         if (chunkOffset[0] & 0xff00)
1913         {
1914            printf("Weird!  The top byte of the chunkType has a value %04x!\n", chunkOffset[0]);
1915            continue;
1916         }
1917
1918         // Debug - Colors polygons with certain flags bright blue! ajg
1919         polys[*numPolys].debugColor = 0;
1920         //polys[*numPolys].debugColor = tdColor;
1921
1922         // Debug - ajg
1923         //printf("%d (%08x) : %04x %04x %04x\n", k, address[k]*3*2, chunkOffset[0], chunkOffset[1], chunkOffset[2]);
1924         //break;
1925
1926         // TEXTURE
1927         /* There may be more than just high & low res texture types, so I'm keeping texType as a UINT8. */
1928         if (chunkOffset[1] & 0x1000) polys[*numPolys].texType = 0x1;
1929         else                         polys[*numPolys].texType = 0x0;
1930
1931         polys[*numPolys].texPageSmall       = (chunkOffset[2] & 0x8000) >> 15;  // Just a guess.
1932         polys[*numPolys].texPageHorizOffset = (chunkOffset[2] & 0x3000) >> 12;
1933         polys[*numPolys].texPageVertOffset  = (chunkOffset[2] & 0x0060) >> 5;
1934
1935         polys[*numPolys].texIndex = chunkOffset[1] & 0x000f;
1936
1937
1938         // PALETTE
1939         polys[*numPolys].palOffset = 0;
1940         polys[*numPolys].palPageSize = 0x100;
1941
1942         /* FIXME: This isn't correct.
1943                   Buriki & Xrally need this line.  Roads Edge needs it removed.
1944                   So instead we're looking for a bit that is on for XRally & Buriki, but noone else. */
1945         if (m_3dregs[0x00/4] & 0x2000)
1946         {
1947            if (strcmp(machine().basename(), "roadedge"))
1948               polys[*numPolys].palOffset += 0x800;
1949         }
1950
1951         //UINT16 explicitPaletteValue0 = ((chunkOffset[?] & 0x????) >> ?) * 0x800;
1952         UINT16 explicitPaletteValue1 = ((chunkOffset[1] & 0x0f00) >> 8) * 0x080;
1953         UINT16 explicitPaletteValue2 = ((chunkOffset[1] & 0x00f0) >> 4) * 0x008;
1954
1955         // The presence of 0x00f0 *probably* sets 0x10-sized palette addressing.
1956         if (explicitPaletteValue2) polys[*numPolys].palPageSize = 0x10;
1957
1958         // Apply the dynamic palette offset if its flag is set, otherwise stick with the fixed one
1959         if ((packet[1] & 0x0100))
1960         {
1961            explicitPaletteValue1 = m_paletteState3d * 0x80;
1962            explicitPaletteValue2 = 0;      // This is probably hiding somewhere in operation 0011
1963         }
1964
1965         polys[*numPolys].palOffset += (explicitPaletteValue1 + explicitPaletteValue2);
1966
1967
1968
1969         UINT8 chunkLength = 0;
1970         switch(chunkType)
1971         {
1972         /*/////////////////////////
1973         // CHUNK TYPE BITS - These are very likely incorrect.
1974         // x--- ---- - 1 = Has only 1 vertex (part of a triangle fan/strip)
1975         // -x-- ---- -
1976         // --x- ---- -
1977         // ---x ---- -
1978         // ---- x--- -
1979         // ---- -x-- - 1 = Has per-vert UVs
1980         // ---- --x- -
1981         // ---- ---x - 1 = Has per-vert normals
1982         /////////////////////////*/
1983
1984         // 33 word chunk, 3 vertices, per-vertex UVs & normals, per-face normal
1985         case 0x05:  // 0000 0101
1986         case 0x0f:  // 0000 1111
1987            for (int m = 0; m < 3; m++)
1988            {
1989               polys[*numPolys].vert[m].worldCoords[0] = uToF(chunkOffset[3 + (9*m)]);
1990               polys[*numPolys].vert[m].worldCoords[1] = uToF(chunkOffset[4 + (9*m)]);
1991               polys[*numPolys].vert[m].worldCoords[2] = uToF(chunkOffset[5 + (9*m)]);
1992               polys[*numPolys].vert[m].worldCoords[3] = 1.0f;
1993               polys[*numPolys].n = 3;
1994
1995               // chunkOffset[6 + (9*m)] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select
1996               polys[*numPolys].vert[m].texCoords[0] = uToF(chunkOffset[7 + (9*m)]);
1997               polys[*numPolys].vert[m].texCoords[1] = uToF(chunkOffset[8 + (9*m)]);
1998               polys[*numPolys].vert[m].texCoords[2] = 0.0f;
1999               polys[*numPolys].vert[m].texCoords[3] = 1.0f;
2000
2001               polys[*numPolys].vert[m].normal[0] = uToF(chunkOffset[9  + (9*m)]);
2002               polys[*numPolys].vert[m].normal[1] = uToF(chunkOffset[10 + (9*m)] );
2003               polys[*numPolys].vert[m].normal[2] = uToF(chunkOffset[11 + (9*m)] );
2004               polys[*numPolys].vert[m].normal[3] = 0.0f;
2005            }
2006
2007            // Redundantly called, but it works...
2008            polys[*numPolys].faceNormal[0] = uToF(chunkOffset[30]);
2009            polys[*numPolys].faceNormal[1] = uToF(chunkOffset[31]);
2010            polys[*numPolys].faceNormal[2] = uToF(chunkOffset[32]);
2011            polys[*numPolys].faceNormal[3] = 0.0f;
2012
2013            chunkLength = 33;
2014            break;
2015
2016
2017         // 24 word chunk, 3 vertices, per-vertex UVs
2018         case 0x04:  // 0000 0100
2019         case 0x0e:  // 0000 1110
2020         case 0x24:  // 0010 0100
2021         case 0x2e:  // 0010 1110
2022            for (int m = 0; m < 3; m++)
2023            {
2024               polys[*numPolys].vert[m].worldCoords[0] = uToF(chunkOffset[3 + (6*m)]);
2025               polys[*numPolys].vert[m].worldCoords[1] = uToF(chunkOffset[4 + (6*m)]);
2026               polys[*numPolys].vert[m].worldCoords[2] = uToF(chunkOffset[5 + (6*m)]);
2027               polys[*numPolys].vert[m].worldCoords[3] = 1.0f;
2028               polys[*numPolys].n = 3;
2029
2030               // chunkOffset[6 + (6*m)] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select
2031               polys[*numPolys].vert[m].texCoords[0] = uToF(chunkOffset[7 + (6*m)]);
2032               polys[*numPolys].vert[m].texCoords[1] = uToF(chunkOffset[8 + (6*m)]);
2033               polys[*numPolys].vert[m].texCoords[2] = 0.0f;
2034               polys[*numPolys].vert[m].texCoords[3] = 1.0f;
2035
2036               polys[*numPolys].vert[m].normal[0] = uToF(chunkOffset[21]);
2037               polys[*numPolys].vert[m].normal[1] = uToF(chunkOffset[22]);
2038               polys[*numPolys].vert[m].normal[2] = uToF(chunkOffset[23]);
2039               polys[*numPolys].vert[m].normal[3] = 0.0f;
2040            }
2041
2042            // Redundantly called, but it works...
2043            polys[*numPolys].faceNormal[0] = polys[*numPolys].vert[2].normal[0];
2044            polys[*numPolys].faceNormal[1] = polys[*numPolys].vert[2].normal[1];
2045            polys[*numPolys].faceNormal[2] = polys[*numPolys].vert[2].normal[2];
2046            polys[*numPolys].faceNormal[3] = 0.0f;
2047
2048            chunkLength = 24;
2049            break;
2050
2051
2052         // 15 word chunk, 1 vertex, per-vertex UVs & normals, face normal
2053         case 0x87:  // 1000 0111
2054         case 0x97:  // 1001 0111
2055         case 0xd7:  // 1101 0111
2056         case 0xc7:  // 1100 0111
2057            // Copy over the proper vertices from the previous triangle...
2058            memcpy(&polys[*numPolys].vert[1], &lastPoly.vert[0], sizeof(struct polyVert));
2059            memcpy(&polys[*numPolys].vert[2], &lastPoly.vert[2], sizeof(struct polyVert));
2060
2061            // Fill in the appropriate data...
2062            polys[*numPolys].vert[0].worldCoords[0] = uToF(chunkOffset[3]);
2063            polys[*numPolys].vert[0].worldCoords[1] = uToF(chunkOffset[4]);
2064            polys[*numPolys].vert[0].worldCoords[2] = uToF(chunkOffset[5]);
2065            polys[*numPolys].vert[0].worldCoords[3] = 1.0f;
2066            polys[*numPolys].n = 3;
2067
2068            // chunkOffset[6] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select
2069            polys[*numPolys].vert[0].texCoords[0] = uToF(chunkOffset[7]);
2070            polys[*numPolys].vert[0].texCoords[1] = uToF(chunkOffset[8]);
2071            polys[*numPolys].vert[0].texCoords[2] = 0.0f;
2072            polys[*numPolys].vert[0].texCoords[3] = 1.0f;
2073
2074            polys[*numPolys].vert[0].normal[0] = uToF(chunkOffset[9]);
2075            polys[*numPolys].vert[0].normal[1] = uToF(chunkOffset[10]);
2076            polys[*numPolys].vert[0].normal[2] = uToF(chunkOffset[11]);
2077            polys[*numPolys].vert[0].normal[3] = 0.0f;
2078
2079            polys[*numPolys].faceNormal[0] = uToF(chunkOffset[12]);
2080            polys[*numPolys].faceNormal[1] = uToF(chunkOffset[13]);
2081            polys[*numPolys].faceNormal[2] = uToF(chunkOffset[14]);
2082            polys[*numPolys].faceNormal[3] = 0.0f;
2083
2084            chunkLength = 15;
2085            break;
2086
2087
2088         // 12 word chunk, 1 vertex, per-vertex UVs
2089         case 0x86:  // 1000 0110
2090         case 0x96:  // 1001 0110
2091         case 0xb6:  // 1011 0110
2092         case 0xc6:  // 1100 0110
2093         case 0xd6:  // 1101 0110
2094            // Copy over the proper vertices from the previous triangle...
2095            memcpy(&polys[*numPolys].vert[1], &lastPoly.vert[0], sizeof(struct polyVert));
2096            memcpy(&polys[*numPolys].vert[2], &lastPoly.vert[2], sizeof(struct polyVert));
2097
2098            polys[*numPolys].vert[0].worldCoords[0] = uToF(chunkOffset[3]);
2099            polys[*numPolys].vert[0].worldCoords[1] = uToF(chunkOffset[4]);
2100            polys[*numPolys].vert[0].worldCoords[2] = uToF(chunkOffset[5]);
2101            polys[*numPolys].vert[0].worldCoords[3] = 1.0f;
2102            polys[*numPolys].n = 3;
2103
2104            // chunkOffset[6] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select
2105            polys[*numPolys].vert[0].texCoords[0] = uToF(chunkOffset[7]);
2106            polys[*numPolys].vert[0].texCoords[1] = uToF(chunkOffset[8]);
2107            polys[*numPolys].vert[0].texCoords[2] = 0.0f;
2108            polys[*numPolys].vert[0].texCoords[3] = 1.0f;
2109
2110            // This normal could be right, but I'm not entirely sure - there is no normal in the 18 bytes!
2111            polys[*numPolys].vert[0].normal[0] = lastPoly.faceNormal[0];
2112            polys[*numPolys].vert[0].normal[1] = lastPoly.faceNormal[1];
2113            polys[*numPolys].vert[0].normal[2] = lastPoly.faceNormal[2];
2114            polys[*numPolys].vert[0].normal[3] = lastPoly.faceNormal[3];
2115
2116            polys[*numPolys].faceNormal[0] = lastPoly.faceNormal[0];
2117            polys[*numPolys].faceNormal[1] = lastPoly.faceNormal[1];
2118            polys[*numPolys].faceNormal[2] = lastPoly.faceNormal[2];
2119            polys[*numPolys].faceNormal[3] = lastPoly.faceNormal[3];
2120
2121            // TODO: I'm not reading 3 necessary words here (maybe face normal) !!!
2122
2123#if 0
2124            // DEBUG
2125            printf("0x?6 : %08x (%d/%d)\n", address[k]*3*2, l, size[k]-1);
2126            for (int m = 0; m < 13; m++)
2127               printf("%04x ", chunkOffset[m]);
2128            printf("\n");
2129
2130            for (int m = 0; m < 13; m++)
2131               printf("%3.4f ", uToF(chunkOffset[m]));
2132            printf("\n\n");
2133#endif
2134
2135            chunkLength = 12;
2136            break;
2137
2138         default:
2139            printf("UNKNOWN geometry CHUNK TYPE : %02x\n", chunkType);
2140            chunkLength = 0;
2141            break;
2142         }
2143
2144         polys[*numPolys].visible = 1;
2145
2146         // Backup the last polygon (for triangle fans [strips?])
2147         memcpy(&lastPoly, &polys[*numPolys], sizeof(struct polygon));
2148
2149
2150         ////////////////////////////////////
2151         // Project and clip               //
2152         ////////////////////////////////////
2153         // Perform the world transformations...
2154         // !! Can eliminate this step with a matrix stack (maybe necessary?) !!
2155         setIdentity(m_modelViewMatrix);
2156         if (m_mcu_type != SAMSHO_MCU)
2157         {
2158            // The sams64 games transform the geometry in front of a stationary camera.
2159            // This is fine in sams64_2, since it never calls the 'camera transformation' function
2160            // (thus using the identity matrix for this transform), but sams64 calls the
2161            // camera transformation function with rotation values.
2162            // It remains to be seen what those might do...
2163            matmul4(m_modelViewMatrix, m_modelViewMatrix, m_cameraMatrix);
2164         }
2165         matmul4(m_modelViewMatrix, m_modelViewMatrix, objectMatrix);
2166
2167         // LIGHTING
2168         if (packet[1] & 0x0008 && m_lightStrength > 0.0f)
2169         {
2170            for (int v = 0; v < 3; v++)
2171            {
2172               float transformedNormal[4];
2173               vecmatmul4(transformedNormal, objectMatrix, polys[*numPolys].vert[v].normal);
2174               normalize(transformedNormal);
2175               normalize(m_lightVector);
2176
2177               float intensity = vecDotProduct(transformedNormal, m_lightVector) * -1.0f;
2178               intensity = (intensity <= 0.0f) ? (0.0f) : (intensity);
2179               intensity *= m_lightStrength * 128.0f;    // Turns 0x0100 into 1.0
2180               intensity *= 128.0;                     // Maps intensity to the range [0.0, 2.0]
2181               if (intensity >= 255.0f) intensity = 255.0f;
2182
2183               polys[*numPolys].vert[v].light[0] = intensity;
2184               polys[*numPolys].vert[v].light[1] = intensity;
2185               polys[*numPolys].vert[v].light[2] = intensity;
2186            }
2187         }
2188         else
2189         {
2190            // Just clear out the light values
2191            for (int v = 0; v < 3; v++)
2192            {
2193               polys[*numPolys].vert[v].light[0] = 0;
2194               polys[*numPolys].vert[v].light[1] = 0;
2195               polys[*numPolys].vert[v].light[2] = 0;
2196            }
2197         }
2198
2199
2200         // BACKFACE CULL //
2201         // EMPIRICAL EVIDENCE SEEMS TO SHOW THE HNG64 HARDWARE DOES NOT BACKFACE CULL //
2202#if 0
2203         float cullRay[4];
2204         float cullNorm[4];
2205
2206         // Cast a ray out of the camera towards the polygon's point in eyespace.
2207         vecmatmul4(cullRay, modelViewMatrix, polys[*numPolys].vert[0].worldCoords);
2208         normalize(cullRay);
2209         // Dot product that with the normal to see if you're negative...
2210         vecmatmul4(cullNorm, modelViewMatrix, polys[*numPolys].faceNormal);
2211
2212         float result = vecDotProduct(cullRay, cullNorm);
2213
2214         if (result < 0.0f)
2215            polys[*numPolys].visible = 1;
2216         else
2217            polys[*numPolys].visible = 0;
2218#endif
2219
2220
2221         // BEHIND-THE-CAMERA CULL //
2222         vecmatmul4(cullRay, m_modelViewMatrix, polys[*numPolys].vert[0].worldCoords);
2223         if (cullRay[2] > 0.0f)              // Camera is pointing down -Z
2224         {
2225            polys[*numPolys].visible = 0;
2226         }
2227
2228
2229         // TRANSFORM THE TRIANGLE INTO HOMOGENEOUS SCREEN SPACE //
2230         if (polys[*numPolys].visible)
2231         {
2232            for (int m = 0; m < polys[*numPolys].n; m++)
2233            {
2234               // Transform and project the vertex into pre-divided homogeneous coordinates...
2235               vecmatmul4(eyeCoords, m_modelViewMatrix, polys[*numPolys].vert[m].worldCoords);
2236               vecmatmul4(polys[*numPolys].vert[m].clipCoords, m_projectionMatrix, eyeCoords);
2237            }
2238
2239            if (polys[*numPolys].visible)
2240            {
2241               // Clip the triangles to the view frustum...
2242               performFrustumClip(&polys[*numPolys]);
2243
2244               for (int m = 0; m < polys[*numPolys].n; m++)
2245               {
2246                  // Convert into normalized device coordinates...
2247                  ndCoords[0] = polys[*numPolys].vert[m].clipCoords[0] / polys[*numPolys].vert[m].clipCoords[3];
2248                  ndCoords[1] = polys[*numPolys].vert[m].clipCoords[1] / polys[*numPolys].vert[m].clipCoords[3];
2249                  ndCoords[2] = polys[*numPolys].vert[m].clipCoords[2] / polys[*numPolys].vert[m].clipCoords[3];
2250                  ndCoords[3] = polys[*numPolys].vert[m].clipCoords[3];
2251
2252                  // Final pixel values are garnered here :
2253                  windowCoords[0] = (ndCoords[0]+1.0f) * ((float)(visarea.max_x) / 2.0f) + 0.0f;
2254                  windowCoords[1] = (ndCoords[1]+1.0f) * ((float)(visarea.max_y) / 2.0f) + 0.0f;
2255                  windowCoords[2] = (ndCoords[2]+1.0f) * 0.5f;
2256
2257                  windowCoords[1] = (float)visarea.max_y - windowCoords[1];       // Flip Y
2258
2259                  // Store the points in a list for later use...
2260                  polys[*numPolys].vert[m].clipCoords[0] = windowCoords[0];
2261                  polys[*numPolys].vert[m].clipCoords[1] = windowCoords[1];
2262                  polys[*numPolys].vert[m].clipCoords[2] = windowCoords[2];
2263                  polys[*numPolys].vert[m].clipCoords[3] = ndCoords[3];
2264               }
2265            }
2266         }
2267
2268         // Advance to the next polygon chunk...
2269         chunkOffset += chunkLength;
2270
2271         (*numPolys)++;
2272      }
2273   }
2274}
2275
2276void hng64_state::hng64_command3d(const UINT16* packet)
2277{
2278
2279   /* A temporary place to put some polygons.  This will optimize away if the compiler's any good. */
2280   int numPolys = 0;
2281   dynamic_array<polygon> polys(1024*5);
2282
2283   //printf("packet type : %04x %04x|%04x %04x|%04x %04x|%04x %04x  | %04x %04x %04x %04x %04x %04x %04x %04x\n", packet[0],packet[1],packet[2],packet[3],packet[4],packet[5],packet[6],packet[7],     packet[8], packet[9], packet[10], packet[11], packet[12], packet[13], packet[14], packet[15]);
2284   
2285   switch (packet[0])
2286   {
2287   case 0x0000:    // Appears to be a NOP.
2288      break;
2289
2290   case 0x0001:    // Camera transformation.
2291      setCameraTransformation(packet);
2292      break;
2293
2294   case 0x0010:    // Lighting information.
2295      //if (packet[9]) printPacket(packet, 1);
2296      setLighting(packet);
2297      break;
2298
2299   case 0x0011:    // Palette / Model flags?
2300      //printPacket(packet, 1); printf("\n");
2301      set3dFlags(packet);
2302      break;
2303
2304   case 0x0012:    // Projection Matrix
2305      //printPacket(packet, 1);
2306      setCameraProjectionMatrix(packet);
2307      break;
2308
2309   case 0x0100:
2310   case 0x0101:    // Geometry with full transformations
2311      // HACK.  Masks out a piece of geo bbust2's drawShaded() crashes on.
2312      if (packet[2] == 0x0003 && packet[3] == 0x8f37 && m_mcu_type == SHOOT_MCU)
2313         break;
2314
2315      recoverPolygonBlock( packet, polys, &numPolys);
2316      break;
2317
2318   case 0x0102:    // Geometry with only translation
2319      // HACK.  Give up on strange calls to 0102.
2320      if (packet[8] != 0x0102)
2321      {
2322         // It appears as though packet[7] might hold the magic #
2323         // Almost looks like there is a chain mode for these guys.  Same for 0101?
2324         // printf("WARNING: "); printPacket(packet, 1);
2325         break;
2326      }
2327
2328      // Split the packet and call recoverPolygonBlock on each half.
2329      UINT16 miniPacket[16];
2330      memset(miniPacket, 0, sizeof(UINT16)*16);
2331      for (int i = 0; i < 7; i++) miniPacket[i] = packet[i];
2332      miniPacket[7] = 0x7fff;
2333      miniPacket[11] = 0x7fff;
2334      miniPacket[15] = 0x7fff;
2335      recoverPolygonBlock( miniPacket, polys, &numPolys);
2336
2337      memset(miniPacket, 0, sizeof(UINT16)*16);
2338      for (int i = 0; i < 7; i++) miniPacket[i] = packet[i+8];
2339      for (int i = 0; i < 7; i++) miniPacket[i] = packet[i+8];
2340      miniPacket[7] = 0x7fff;
2341      miniPacket[11] = 0x7fff;
2342      miniPacket[15] = 0x7fff;
2343      recoverPolygonBlock( miniPacket, polys, &numPolys);
2344      break;
2345
2346   case 0x1000:    // Unknown: Some sort of global flags?
2347      //printPacket(packet, 1); printf("\n");
2348      break;
2349
2350   case 0x1001:    // Unknown: Some sort of global flags (a group of 4, actually)?
2351      //printPacket(packet, 1);
2352      break;
2353
2354   default:
2355      printf("HNG64: Unknown 3d command %04x.\n", packet[0]);
2356      break;
2357   }
2358
2359   /* If there are polygons, rasterize them into the display buffer */
2360   for (int i = 0; i < numPolys; i++)
2361   {
2362      if (polys[i].visible)
2363      {
2364         //DrawWireframe( &polys[i]);
2365         drawShaded( &polys[i]);
2366      }
2367   }
2368}
2369
2370void hng64_state::clear3d()
2371{
2372   int i;
2373
2374   const rectangle &visarea = m_screen->visible_area();
2375
2376   // Clear each of the display list buffers after drawing - todo: kill!
2377   for (i = 0; i < 0x81; i++)
2378   {
2379      m_dls[0][i] = 0;
2380      m_dls[1][i] = 0;
2381   }
2382
2383   // Reset the buffers...
2384   for (i = 0; i < (visarea.max_x)*(visarea.max_y); i++)
2385   {
2386      m_depthBuffer3d[i] = 100.0f;
2387      m_colorBuffer3d[i] = rgb_t(0, 0, 0, 0);
2388   }
2389
2390   // Set some matrices to the identity...
2391   setIdentity(m_projectionMatrix);
2392   setIdentity(m_modelViewMatrix);
2393   setIdentity(m_cameraMatrix);
2394}
2395
2396/* 3D/framebuffer video registers
2397 * ------------------------------
2398 *
2399 * UINT32 | Bits                                    | Use
2400 *        | 3322 2222 2222 1111 1111 11             |
2401 * -------+-1098-7654-3210-9876-5432-1098-7654-3210-+----------------
2402 *      0 | ---- --x- ---- ---- ---- ---- ---- ---- | Reads in Fatal Fury WA, if on then there isn't a 3d refresh (busy flag?).
2403 *      0 | ---- ---x ---- ---- ---- ---- ---- ---- | set at POST/service modes, almost likely fb disable
2404 *      0 | ???? ???? ???? ???? ccc? ???? ???? ???? | framebuffer color base, 0x311800 in Fatal Fury WA, 0x313800 in Buriki One
2405 *      1 |                                         |
2406 *      2 | ???? ???? ???? ???? ???? ???? ???? ???? | camera / framebuffer global x/y? Actively used by Samurai Shodown 64 2
2407 *      3 | ---- --?x ---- ---- ---- ---- ---- ---- | unknown, unsetted by Buriki One and setted by Fatal Fury WA, buffering mode?
2408 *   4-11 | ---- ???? ---- ???? ---- ???? ---- ???? | Table filled with 0x0? data
2409 *
2410 */
2411
2412/////////////////////
2413// 3D UTILITY CODE //
2414/////////////////////
2415
2416/* 4x4 matrix multiplication */
2417static void matmul4(float *product, const float *a, const float *b )
2418{
2419   int i;
2420   for (i = 0; i < 4; i++)
2421   {
2422      const float ai0 = a[0  + i];
2423      const float ai1 = a[4  + i];
2424      const float ai2 = a[8  + i];
2425      const float ai3 = a[12 + i];
2426
2427      product[0  + i] = ai0 * b[0 ] + ai1 * b[1 ] + ai2 * b[2 ] + ai3 * b[3 ];
2428      product[4  + i] = ai0 * b[4 ] + ai1 * b[5 ] + ai2 * b[6 ] + ai3 * b[7 ];
2429      product[8  + i] = ai0 * b[8 ] + ai1 * b[9 ] + ai2 * b[10] + ai3 * b[11];
2430      product[12 + i] = ai0 * b[12] + ai1 * b[13] + ai2 * b[14] + ai3 * b[15];
2431   }
2432}
2433
2434/* vector by 4x4 matrix multiply */
2435static void vecmatmul4(float *product, const float *a, const float *b)
2436{
2437   const float bi0 = b[0];
2438   const float bi1 = b[1];
2439   const float bi2 = b[2];
2440   const float bi3 = b[3];
2441
2442   product[0] = bi0 * a[0] + bi1 * a[4] + bi2 * a[8 ] + bi3 * a[12];
2443   product[1] = bi0 * a[1] + bi1 * a[5] + bi2 * a[9 ] + bi3 * a[13];
2444   product[2] = bi0 * a[2] + bi1 * a[6] + bi2 * a[10] + bi3 * a[14];
2445   product[3] = bi0 * a[3] + bi1 * a[7] + bi2 * a[11] + bi3 * a[15];
2446}
2447
2448static float vecDotProduct(const float *a, const float *b)
2449{
2450   return ((a[0]*b[0]) + (a[1]*b[1]) + (a[2]*b[2]));
2451}
2452
2453static void setIdentity(float *matrix)
2454{
2455   int i;
2456
2457   for (i = 0; i < 16; i++)
2458   {
2459      matrix[i] = 0.0f;
2460   }
2461
2462   matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1.0f;
2463}
2464
2465static float uToF(UINT16 input)
2466{
2467   float retVal;
2468   retVal = (float)((INT16)input) / 32768.0f;
2469   return retVal;
2470
2471#if 0
2472   if ((INT16)input < 0)
2473      retVal = (float)((INT16)input) / 32768.0f;
2474   else
2475      retVal = (float)((INT16)input) / 32767.0f;
2476#endif
2477}
2478
2479static void normalize(float* x)
2480{
2481   double l2 = (x[0]*x[0]) + (x[1]*x[1]) + (x[2]*x[2]);
2482   double l = sqrt(l2);
2483
2484   x[0] = (float)(x[0] / l);
2485   x[1] = (float)(x[1] / l);
2486   x[2] = (float)(x[2] / l);
2487}
2488
2489
2490
2491///////////////////////////
2492// POLYGON CLIPPING CODE //
2493///////////////////////////
2494
2495///////////////////////////////////////////////////////////////////////////////////
2496// The remainder of the code in this file is heavily                             //
2497//   influenced by, and sometimes copied verbatim from Andrew Zaferakis' SoftGL  //
2498//   rasterizing system.                                                         //
2499//                                                                               //
2500//   Andrew granted permission for its use in MAME in October of 2004.           //
2501///////////////////////////////////////////////////////////////////////////////////
2502
2503// Refer to the clipping planes as numbers
2504#define HNG64_LEFT   0
2505#define HNG64_RIGHT  1
2506#define HNG64_TOP    2
2507#define HNG64_BOTTOM 3
2508#define HNG64_NEAR   4
2509#define HNG64_FAR    5
2510
2511
2512static int Inside(struct polyVert *v, int plane)
2513{
2514   switch(plane)
2515   {
2516   case HNG64_LEFT:
2517      return (v->clipCoords[0] >= -v->clipCoords[3]) ? 1 : 0;
2518   case HNG64_RIGHT:
2519      return (v->clipCoords[0] <=  v->clipCoords[3]) ? 1 : 0;
2520
2521   case HNG64_TOP:
2522      return (v->clipCoords[1] <=  v->clipCoords[3]) ? 1 : 0;
2523   case HNG64_BOTTOM:
2524      return (v->clipCoords[1] >= -v->clipCoords[3]) ? 1 : 0;
2525
2526   case HNG64_NEAR:
2527      return (v->clipCoords[2] <=  v->clipCoords[3]) ? 1 : 0;
2528   case HNG64_FAR:
2529      return (v->clipCoords[2] >= -v->clipCoords[3]) ? 1 : 0;
2530   }
2531
2532   return 0;
2533}
2534
2535static void Intersect(struct polyVert *input0, struct polyVert *input1, struct polyVert *output, int plane)
2536{
2537   float t = 0.0f;
2538
2539   float *Iv0 = input0->clipCoords;
2540   float *Iv1 = input1->clipCoords;
2541   float *Ov  = output->clipCoords;
2542
2543   float *It0 = input0->texCoords;
2544   float *It1 = input1->texCoords;
2545   float *Ot  = output->texCoords;
2546
2547   float *Il0 = input0->light;
2548   float *Il1 = input1->light;
2549   float *Ol  = output->light;
2550
2551   switch(plane)
2552   {
2553   case HNG64_LEFT:
2554      t = (Iv0[0]+Iv0[3]) / (-Iv1[3]+Iv0[3]-Iv1[0]+Iv0[0]);
2555      break;
2556   case HNG64_RIGHT:
2557      t = (Iv0[0]-Iv0[3]) / (Iv1[3]-Iv0[3]-Iv1[0]+Iv0[0]);
2558      break;
2559   case HNG64_TOP:
2560      t = (Iv0[1]-Iv0[3]) / (Iv1[3]-Iv0[3]-Iv1[1]+Iv0[1]);
2561      break;
2562   case HNG64_BOTTOM:
2563      t = (Iv0[1]+Iv0[3]) / (-Iv1[3]+Iv0[3]-Iv1[1]+Iv0[1]);
2564      break;
2565   case HNG64_NEAR:
2566      t = (Iv0[2]-Iv0[3]) / (Iv1[3]-Iv0[3]-Iv1[2]+Iv0[2]);
2567      break;
2568   case HNG64_FAR:
2569      t = (Iv0[2]+Iv0[3]) / (-Iv1[3]+Iv0[3]-Iv1[2]+Iv0[2]);
2570      break;
2571   }
2572
2573   Ov[0] = Iv0[0] + (Iv1[0] - Iv0[0]) * t;
2574   Ov[1] = Iv0[1] + (Iv1[1] - Iv0[1]) * t;
2575   Ov[2] = Iv0[2] + (Iv1[2] - Iv0[2]) * t;
2576   Ov[3] = Iv0[3] + (Iv1[3] - Iv0[3]) * t;
2577
2578   Ot[0] = It0[0] + (It1[0] - It0[0]) * t;
2579   Ot[1] = It0[1] + (It1[1] - It0[1]) * t;
2580   Ot[2] = It0[2] + (It1[2] - It0[2]) * t;
2581   Ot[3] = It0[3] + (It1[3] - It0[3]) * t;
2582
2583   Ol[0] = Il0[0] + (Il1[0] - Il0[0]) * t;
2584   Ol[1] = Il0[1] + (Il1[1] - Il0[1]) * t;
2585   Ol[2] = Il0[2] + (Il1[2] - Il0[2]) * t;
2586}
2587
2588static void performFrustumClip(struct polygon *p)
2589{
2590   int i, j, k;
2591   //////////////////////////////////////////////////////////////////////////
2592   // Clip against the volumes defined by the homogeneous clip coordinates //
2593   //////////////////////////////////////////////////////////////////////////
2594
2595   struct polygon temp;
2596
2597   struct polyVert *v0;
2598   struct polyVert *v1;
2599   struct polyVert *tv;
2600
2601   temp.n = 0;
2602
2603   // Skip near and far clipping planes ?
2604   for (j = 0; j <= HNG64_BOTTOM; j++)
2605   {
2606      for (i = 0; i < p->n; i++)
2607      {
2608         k = (i+1) % p->n; // Index of next vertex
2609
2610         v0 = &p->vert[i];
2611         v1 = &p->vert[k];
2612
2613         tv = &temp.vert[temp.n];
2614
2615         if (Inside(v0, j) && Inside(v1, j))                         // Edge is completely inside the volume...
2616         {
2617            memcpy(tv, v1, sizeof(struct polyVert));
2618            temp.n++;
2619         }
2620
2621         else if (Inside(v0, j) && !Inside(v1, j))                   // Edge goes from in to out...
2622         {
2623            Intersect(v0, v1, tv, j);
2624            temp.n++;
2625         }
2626
2627         else if (!Inside(v0, j) && Inside(v1, j))                   // Edge goes from out to in...
2628         {
2629            Intersect(v0, v1, tv, j);
2630            memcpy(&temp.vert[temp.n+1], v1, sizeof(struct polyVert));
2631            temp.n+=2;
2632         }
2633      }
2634
2635      p->n = temp.n;
2636
2637      for (i = 0; i < temp.n; i++)
2638      {
2639         memcpy(&p->vert[i], &temp.vert[i], sizeof(struct polyVert));
2640      }
2641
2642      temp.n = 0;
2643   }
2644}
2645
2646
2647/////////////////////////
2648// wireframe rendering //
2649/////////////////////////
2650#ifdef UNUSED_FUNCTION
2651static void plot( INT32 x, INT32 y, UINT32 color)
2652{
2653   UINT32* cb = &(colorBuffer3d[(y * machine.first_screen()->visible_area().max_x) + x]);
2654   *cb = color;
2655}
2656
2657// Stolen from http://en.wikipedia.org/wiki/Bresenham's_line_algorithm (no copyright denoted) - the non-optimized version
2658static void drawline2d( INT32 x0, INT32 y0, INT32 x1, INT32 y1, UINT32 color)
2659{
2660#define SWAP(a,b) tmpswap = a; a = b; b = tmpswap;
2661
2662   INT32 i;
2663   INT32 steep = 1;
2664   INT32 sx, sy;  /* step positive or negative (1 or -1) */
2665   INT32 dx, dy;  /* delta (difference in X and Y between points) */
2666   INT32 e;
2667
2668   /*
2669   * inline swap. On some architectures, the XOR trick may be faster
2670   */
2671   INT32 tmpswap;
2672
2673   /*
2674   * optimize for vertical and horizontal lines here
2675   */
2676
2677   dx = abs(x1 - x0);
2678   sx = ((x1 - x0) > 0) ? 1 : -1;
2679   dy = abs(y1 - y0);
2680   sy = ((y1 - y0) > 0) ? 1 : -1;
2681
2682   if (dy > dx)
2683   {
2684      steep = 0;
2685      SWAP(x0, y0);
2686      SWAP(dx, dy);
2687      SWAP(sx, sy);
2688   }
2689
2690   e = (dy << 1) - dx;
2691
2692   for (i = 0; i < dx; i++)
2693   {
2694      if (steep)
2695      {
2696         plot( x0, y0, color);
2697      }
2698      else
2699      {
2700         plot( y0, x0, color);
2701      }
2702      while (e >= 0)
2703      {
2704         y0 += sy;
2705         e -= (dx << 1);
2706      }
2707
2708      x0 += sx;
2709      e += (dy << 1);
2710   }
2711#undef SWAP
2712}
2713
2714static void DrawWireframe( struct polygon *p)
2715{
2716   int j;
2717   for (j = 0; j < p->n; j++)
2718   {
2719      // osd_printf_debug("now drawing : %f %f %f, %f %f %f\n", p->vert[j].clipCoords[0], p->vert[j].clipCoords[1], p->vert[j].clipCoords[2], p->vert[(j+1)%p->n].clipCoords[0], p->vert[(j+1)%p->n].clipCoords[1], p->vert[(j+1)%p->n].clipCoords[2]);
2720      // osd_printf_debug("%f %f %f %f\n", p->vert[j].clipCoords[0], p->vert[j].clipCoords[1], p->vert[(j+1)%p->n].clipCoords[0], p->vert[(j+1)%p->n].clipCoords[1]);
2721      UINT32 color = rgb_t((UINT8)255, (UINT8)255, (UINT8)0, (UINT8)0);
2722      drawline2d( p->vert[j].clipCoords[0], p->vert[j].clipCoords[1], p->vert[(j+1)%p->n].clipCoords[0], p->vert[(j+1)%p->n].clipCoords[1], color);
2723   }
2724
2725   // SHOWS THE CLIPPING //
2726#if 0
2727   for (int j = 1; j < p->n-1; j++)
2728   {
2729      drawline2d(p->vert[0].clipCoords[0],   p->vert[0].clipCoords[1],   p->vert[j].clipCoords[0],   p->vert[j].clipCoords[1],   255, bitmap);
2730      drawline2d(p->vert[j].clipCoords[0],   p->vert[j].clipCoords[1],   p->vert[j+1].clipCoords[0], p->vert[j+1].clipCoords[1], 255, bitmap);
2731      drawline2d(p->vert[j+1].clipCoords[0], p->vert[j+1].clipCoords[1], p->vert[0].clipCoords[0],   p->vert[0].clipCoords[1],   255, bitmap);
2732   }
2733#endif
2734}
2735#endif
2736
2737
2738/*********************************************************************/
2739/**   FillSmoothTexPCHorizontalLine                                 **/
2740/**     Input: Color Buffer (framebuffer), depth buffer, width and  **/
2741/**            height of framebuffer, starting, and ending values   **/
2742/**            for x and y, constant y.  Fills horizontally with    **/
2743/**            z,r,g,b interpolation.                               **/
2744/**                                                                 **/
2745/**     Output: none                                                **/
2746/*********************************************************************/
2747inline void hng64_state::FillSmoothTexPCHorizontalLine(
2748                                 const polygonRasterOptions& prOptions,
2749                                 int x_start, int x_end, int y, float z_start, float z_delta,
2750                                 float w_start, float w_delta, float r_start, float r_delta,
2751                                 float g_start, float g_delta, float b_start, float b_delta,
2752                                 float s_start, float s_delta, float t_start, float t_delta)
2753{
2754   float*  db = &(m_depthBuffer3d[(y * m_screen->visible_area().max_x) + x_start]);
2755   UINT32* cb = &(m_colorBuffer3d[(y * m_screen->visible_area().max_x) + x_start]);
2756
2757   UINT8 paletteEntry = 0;
2758   float t_coord, s_coord;
2759   const UINT8 *gfx = memregion("textures")->base();
2760   const UINT8 *textureOffset = &gfx[prOptions.texIndex * 1024 * 1024];
2761
2762   for (; x_start <= x_end; x_start++)
2763   {
2764      if (z_start < (*db))
2765      {
2766         // MULTIPLY BACK THROUGH BY W
2767         t_coord = t_start / w_start;
2768         s_coord = s_start / w_start;
2769
2770         if ((prOptions.debugColor & 0xff000000) == 0x01000000)
2771         {
2772            // UV COLOR MODE
2773            *cb = rgb_t(255, (UINT8)(s_coord*255.0f), (UINT8)(t_coord*255.0f), (UINT8)(0));
2774            *db = z_start;
2775         }
2776         else if ((prOptions.debugColor & 0xff000000) == 0x02000000)
2777         {
2778            // Lit
2779            *cb = rgb_t(255, (UINT8)(r_start/w_start), (UINT8)(g_start/w_start), (UINT8)(b_start/w_start));
2780            *db = z_start;
2781         }
2782         else if ((prOptions.debugColor & 0xff000000) == 0xff000000)
2783         {
2784            // DEBUG COLOR MODE
2785            *cb = prOptions.debugColor;
2786            *db = z_start;
2787         }
2788         else
2789         {
2790            float textureS = 0.0f;
2791            float textureT = 0.0f;
2792
2793            // Standard & Half-Res textures
2794            if (prOptions.texType == 0x0)
2795            {
2796               textureS = s_coord * 1024.0f;
2797               textureT = t_coord * 1024.0f;
2798            }
2799            else if (prOptions.texType == 0x1)
2800            {
2801               textureS = s_coord * 512.0f;
2802               textureT = t_coord * 512.0f;
2803            }
2804
2805            // Small-Page textures
2806            if (prOptions.texPageSmall)
2807            {
2808               textureT = fmod(textureT, 256.0f);
2809               textureS = fmod(textureS, 256.0f);
2810
2811               textureT += (256.0f * prOptions.texPageHorizOffset);
2812               textureS += (256.0f * prOptions.texPageVertOffset);
2813            }
2814            paletteEntry = textureOffset[((int)textureS)*1024 + (int)textureT];
2815
2816            // Naieve Alpha Implementation (?) - don't draw if you're at texture index 0...
2817            if (paletteEntry != 0)
2818            {
2819               // The color out of the texture
2820               paletteEntry %= prOptions.palPageSize;
2821               rgb_t color = m_palette->pen(prOptions.palOffset + paletteEntry);
2822
2823               // Apply the lighting
2824               float rIntensity = (r_start/w_start) / 255.0f;
2825               float gIntensity = (g_start/w_start) / 255.0f;
2826               float bIntensity = (b_start/w_start) / 255.0f;
2827               float red   = color.r()   * rIntensity;
2828               float green = color.g() * gIntensity;
2829               float blue  = color.b()  * bIntensity;
2830
2831               // Clamp and finalize
2832               red = color.r() + red;
2833               green = color.g() + green;
2834               blue = color.b() + blue;
2835
2836               if (red >= 255) red = 255;
2837               if (green >= 255) green = 255;
2838               if (blue >= 255) blue = 255;
2839
2840               color = rgb_t(255, (UINT8)red, (UINT8)green, (UINT8)blue);
2841
2842               *cb = color;
2843               *db = z_start;
2844            }
2845         }
2846      }
2847      db++;
2848      cb++;
2849      z_start += z_delta;
2850      w_start += w_delta;
2851      r_start += r_delta;
2852      g_start += g_delta;
2853      b_start += b_delta;
2854      s_start += s_delta;
2855      t_start += t_delta;
2856   }
2857}
2858
2859//----------------------------------------------------------------------------
2860// Given 3D triangle ABC in screen space with clipped coordinates within the following
2861// bounds: x in [0,W], y in [0,H], z in [0,1]. The origin for (x,y) is in the bottom
2862// left corner of the pixel grid. z=0 is the near plane and z=1 is the far plane,
2863// so lesser values are closer. The coordinates of the pixels are evenly spaced
2864// in x and y 1 units apart starting at the bottom-left pixel with coords
2865// (0.5,0.5). In other words, the pixel sample point is in the center of the
2866// rectangular grid cell containing the pixel sample. The framebuffer has
2867// dimensions width x height (WxH). The Color buffer is a 1D array (row-major
2868// order) with 3 unsigned chars per pixel (24-bit color). The Depth buffer is
2869// a 1D array (also row-major order) with a float value per pixel
2870// For a pixel location (x,y) we can obtain
2871// the Color and Depth array locations as: Color[(((int)y)*W+((int)x))*3]
2872// (for the red value, green is offset +1, and blue is offset +2 and
2873// Depth[((int)y)*W+((int)x)]. Fills the pixels contained in the triangle
2874// with the global current color and the properly linearly interpolated depth
2875// value (performs Z-buffer depth test before writing new pixel).
2876// Pixel samples that lie inside the triangle edges are filled with
2877// a bias towards the minimum values (samples that lie exactly on a triangle
2878// edge are filled only for minimum x values along a horizontal span and for
2879// minimum y values, samples lying on max values are not filled).
2880// Per-vertex colors are RGB floating point triplets in [0.0,255.0]. The vertices
2881// include their w-components for use in linearly interpolating perspectively
2882// correct color (RGB) and texture-coords (st) across the face of the triangle.
2883// A texture image of RGB floating point triplets of size TWxWH is also given.
2884// Texture colors are normalized RGB values in [0,1].
2885//   clamp and repeat wrapping modes : Wrapping={0,1}
2886//   nearest and bilinear filtering: Filtering={0,1}
2887//   replace and modulate application modes: Function={0,1}
2888//---------------------------------------------------------------------------
2889void hng64_state::RasterizeTriangle_SMOOTH_TEX_PC(
2890                                 float A[4], float B[4], float C[4],
2891                                 float Ca[3], float Cb[3], float Cc[3], // PER-VERTEX RGB COLORS
2892                                 float Ta[2], float Tb[2], float Tc[2], // PER-VERTEX (S,T) TEX-COORDS
2893                                 const polygonRasterOptions& prOptions)
2894{
2895   // Get our order of points by increasing y-coord
2896   float *p_min = ((A[1] <= B[1]) && (A[1] <= C[1])) ? A : ((B[1] <= A[1]) && (B[1] <= C[1])) ? B : C;
2897   float *p_max = ((A[1] >= B[1]) && (A[1] >= C[1])) ? A : ((B[1] >= A[1]) && (B[1] >= C[1])) ? B : C;
2898   float *p_mid = ((A != p_min) && (A != p_max)) ? A : ((B != p_min) && (B != p_max)) ? B : C;
2899
2900   // Perspectively correct color interpolation, interpolate r/w, g/w, b/w, then divide by 1/w at each pixel (A[3] = 1/w)
2901   float ca[3], cb[3], cc[3];
2902   float ta[2], tb[2], tc[2];
2903
2904   float *c_min;
2905   float *c_mid;
2906   float *c_max;
2907
2908   // We must keep the tex coords straight with the point ordering
2909   float *t_min;
2910   float *t_mid;
2911   float *t_max;
2912
2913   // Find out control points for y, this divides the triangle into upper and lower
2914   int   y_min;
2915   int   y_max;
2916   int   y_mid;
2917
2918   // Compute the slopes of each line, and color this is used to determine the interpolation
2919   float x1_slope;
2920   float x2_slope;
2921   float z1_slope;
2922   float z2_slope;
2923   float w1_slope;
2924   float w2_slope;
2925   float r1_slope;
2926   float r2_slope;
2927   float g1_slope;
2928   float g2_slope;
2929   float b1_slope;
2930   float b2_slope;
2931   float s1_slope;
2932   float s2_slope;
2933   float t1_slope;
2934   float t2_slope;
2935
2936   // Compute the t values used in the equation Ax = Ax + (Bx - Ax)*t
2937   // We only need one t, because it is only used to compute the start.
2938   // Create storage for the interpolated x and z values for both lines
2939   // also for the RGB interpolation
2940   float t;
2941   float x1_interp;
2942   float z1_interp;
2943   float w1_interp;
2944   float r1_interp;
2945   float g1_interp;
2946   float b1_interp;
2947   float s1_interp;
2948   float t1_interp;
2949
2950   float x2_interp;
2951   float z2_interp;
2952   float w2_interp;
2953   float r2_interp;
2954   float g2_interp;
2955   float b2_interp;
2956   float s2_interp;
2957   float t2_interp;
2958
2959   // Create storage for the horizontal interpolation of z and RGB color and its starting points
2960   // This is used to fill the triangle horizontally
2961   int   x_start,     x_end;
2962   float z_interp_x,  z_delta_x;
2963   float w_interp_x,  w_delta_x;
2964   float r_interp_x,  r_delta_x;
2965   float g_interp_x,  g_delta_x;
2966   float b_interp_x,  b_delta_x;
2967   float s_interp_x,  s_delta_x;
2968   float t_interp_x,  t_delta_x;
2969
2970   ca[0] = Ca[0]; ca[1] = Ca[1]; ca[2] = Ca[2];
2971   cb[0] = Cb[0]; cb[1] = Cb[1]; cb[2] = Cb[2];
2972   cc[0] = Cc[0]; cc[1] = Cc[1]; cc[2] = Cc[2];
2973
2974   // Perspectively correct tex interpolation, interpolate s/w, t/w, then divide by 1/w at each pixel (A[3] = 1/w)
2975   ta[0] = Ta[0]; ta[1] = Ta[1];
2976   tb[0] = Tb[0]; tb[1] = Tb[1];
2977   tc[0] = Tc[0]; tc[1] = Tc[1];
2978
2979   // We must keep the colors straight with the point ordering
2980   c_min = (p_min == A) ? ca : (p_min == B) ? cb : cc;
2981   c_mid = (p_mid == A) ? ca : (p_mid == B) ? cb : cc;
2982   c_max = (p_max == A) ? ca : (p_max == B) ? cb : cc;
2983
2984   // We must keep the tex coords straight with the point ordering
2985   t_min = (p_min == A) ? ta : (p_min == B) ? tb : tc;
2986   t_mid = (p_mid == A) ? ta : (p_mid == B) ? tb : tc;
2987   t_max = (p_max == A) ? ta : (p_max == B) ? tb : tc;
2988
2989   // Find out control points for y, this divides the triangle into upper and lower
2990   y_min  = (((int)p_min[1]) + 0.5 >= p_min[1]) ? (int)p_min[1] : ((int)p_min[1]) + 1;
2991   y_max  = (((int)p_max[1]) + 0.5 <  p_max[1]) ? (int)p_max[1] : ((int)p_max[1]) - 1;
2992   y_mid  = (((int)p_mid[1]) + 0.5 >= p_mid[1]) ? (int)p_mid[1] : ((int)p_mid[1]) + 1;
2993
2994   // Compute the slopes of each line, and color this is used to determine the interpolation
2995   x1_slope = (p_max[0] - p_min[0]) / (p_max[1] - p_min[1]);
2996   x2_slope = (p_mid[0] - p_min[0]) / (p_mid[1] - p_min[1]);
2997   z1_slope = (p_max[2] - p_min[2]) / (p_max[1] - p_min[1]);
2998   z2_slope = (p_mid[2] - p_min[2]) / (p_mid[1] - p_min[1]);
2999   w1_slope = (p_max[3] - p_min[3]) / (p_max[1] - p_min[1]);
3000   w2_slope = (p_mid[3] - p_min[3]) / (p_mid[1] - p_min[1]);
3001   r1_slope = (c_max[0] - c_min[0]) / (p_max[1] - p_min[1]);
3002   r2_slope = (c_mid[0] - c_min[0]) / (p_mid[1] - p_min[1]);
3003   g1_slope = (c_max[1] - c_min[1]) / (p_max[1] - p_min[1]);
3004   g2_slope = (c_mid[1] - c_min[1]) / (p_mid[1] - p_min[1]);
3005   b1_slope = (c_max[2] - c_min[2]) / (p_max[1] - p_min[1]);
3006   b2_slope = (c_mid[2] - c_min[2]) / (p_mid[1] - p_min[1]);
3007   s1_slope = (t_max[0] - t_min[0]) / (p_max[1] - p_min[1]);
3008   s2_slope = (t_mid[0] - t_min[0]) / (p_mid[1] - p_min[1]);
3009   t1_slope = (t_max[1] - t_min[1]) / (p_max[1] - p_min[1]);
3010   t2_slope = (t_mid[1] - t_min[1]) / (p_mid[1] - p_min[1]);
3011
3012   // Compute the t values used in the equation Ax = Ax + (Bx - Ax)*t
3013   // We only need one t, because it is only used to compute the start.
3014   // Create storage for the interpolated x and z values for both lines
3015   // also for the RGB interpolation
3016   t = (((float)y_min) + 0.5 - p_min[1]) / (p_max[1] - p_min[1]);
3017   x1_interp = p_min[0] + (p_max[0] - p_min[0]) * t;
3018   z1_interp = p_min[2] + (p_max[2] - p_min[2]) * t;
3019   w1_interp = p_min[3] + (p_max[3] - p_min[3]) * t;
3020   r1_interp = c_min[0] + (c_max[0] - c_min[0]) * t;
3021   g1_interp = c_min[1] + (c_max[1] - c_min[1]) * t;
3022   b1_interp = c_min[2] + (c_max[2] - c_min[2]) * t;
3023   s1_interp = t_min[0] + (t_max[0] - t_min[0]) * t;
3024   t1_interp = t_min[1] + (t_max[1] - t_min[1]) * t;
3025
3026   t = (((float)y_min) + 0.5 - p_min[1]) / (p_mid[1] - p_min[1]);
3027   x2_interp = p_min[0] + (p_mid[0] - p_min[0]) * t;
3028   z2_interp = p_min[2] + (p_mid[2] - p_min[2]) * t;
3029   w2_interp = p_min[3] + (p_mid[3] - p_min[3]) * t;
3030   r2_interp = c_min[0] + (c_mid[0] - c_min[0]) * t;
3031   g2_interp = c_min[1] + (c_mid[1] - c_min[1]) * t;
3032   b2_interp = c_min[2] + (c_mid[2] - c_min[2]) * t;
3033   s2_interp = t_min[0] + (t_mid[0] - t_min[0]) * t;
3034   t2_interp = t_min[1] + (t_mid[1] - t_min[1]) * t;
3035
3036   // First work on the bottom half of the triangle
3037   // I'm using y_min as the incrementer because it saves space and we don't need it anymore
3038   for (; y_min < y_mid; y_min++) {
3039      // We always want to fill left to right, so we have 2 main cases
3040      // Compute the integer starting and ending points and the appropriate z by
3041      // interpolating.  Remember the pixels are in the middle of the grid, i.e. (0.5,0.5,0.5)
3042      if (x1_interp < x2_interp) {
3043         x_start    = ((((int)x1_interp) + 0.5) >= x1_interp) ? (int)x1_interp : ((int)x1_interp) + 1;
3044         x_end      = ((((int)x2_interp) + 0.5) <  x2_interp) ? (int)x2_interp : ((int)x2_interp) - 1;
3045         z_delta_x  = (z2_interp - z1_interp) / (x2_interp - x1_interp);
3046         w_delta_x  = (w2_interp - w1_interp) / (x2_interp - x1_interp);
3047         r_delta_x  = (r2_interp - r1_interp) / (x2_interp - x1_interp);
3048         g_delta_x  = (g2_interp - g1_interp) / (x2_interp - x1_interp);
3049         b_delta_x  = (b2_interp - b1_interp) / (x2_interp - x1_interp);
3050         s_delta_x  = (s2_interp - s1_interp) / (x2_interp - x1_interp);
3051         t_delta_x  = (t2_interp - t1_interp) / (x2_interp - x1_interp);
3052         t          = (x_start + 0.5 - x1_interp) / (x2_interp - x1_interp);
3053         z_interp_x = z1_interp + (z2_interp - z1_interp) * t;
3054         w_interp_x = w1_interp + (w2_interp - w1_interp) * t;
3055         r_interp_x = r1_interp + (r2_interp - r1_interp) * t;
3056         g_interp_x = g1_interp + (g2_interp - g1_interp) * t;
3057         b_interp_x = b1_interp + (b2_interp - b1_interp) * t;
3058         s_interp_x = s1_interp + (s2_interp - s1_interp) * t;
3059         t_interp_x = t1_interp + (t2_interp - t1_interp) * t;
3060
3061      } else {
3062         x_start    = ((((int)x2_interp) + 0.5) >= x2_interp) ? (int)x2_interp : ((int)x2_interp) + 1;
3063         x_end      = ((((int)x1_interp) + 0.5) <  x1_interp) ? (int)x1_interp : ((int)x1_interp) - 1;
3064         z_delta_x  = (z1_interp - z2_interp) / (x1_interp - x2_interp);
3065         w_delta_x  = (w1_interp - w2_interp) / (x1_interp - x2_interp);
3066         r_delta_x  = (r1_interp - r2_interp) / (x1_interp - x2_interp);
3067         g_delta_x  = (g1_interp - g2_interp) / (x1_interp - x2_interp);
3068         b_delta_x  = (b1_interp - b2_interp) / (x1_interp - x2_interp);
3069         s_delta_x  = (s1_interp - s2_interp) / (x1_interp - x2_interp);
3070         t_delta_x  = (t1_interp - t2_interp) / (x1_interp - x2_interp);
3071         t          = (x_start + 0.5 - x2_interp) / (x1_interp - x2_interp);
3072         z_interp_x = z2_interp + (z1_interp - z2_interp) * t;
3073         w_interp_x = w2_interp + (w1_interp - w2_interp) * t;
3074         r_interp_x = r2_interp + (r1_interp - r2_interp) * t;
3075         g_interp_x = g2_interp + (g1_interp - g2_interp) * t;
3076         b_interp_x = b2_interp + (b1_interp - b2_interp) * t;
3077         s_interp_x = s2_interp + (s1_interp - s2_interp) * t;
3078         t_interp_x = t2_interp + (t1_interp - t2_interp) * t;
3079      }
3080
3081      // Pass the horizontal line to the filler, this could be put in the routine
3082      // then interpolate for the next values of x and z
3083      FillSmoothTexPCHorizontalLine( prOptions,
3084         x_start, x_end, y_min, z_interp_x, z_delta_x, w_interp_x, w_delta_x,
3085         r_interp_x, r_delta_x, g_interp_x, g_delta_x, b_interp_x, b_delta_x,
3086         s_interp_x, s_delta_x, t_interp_x, t_delta_x);
3087      x1_interp += x1_slope;   z1_interp += z1_slope;
3088      x2_interp += x2_slope;   z2_interp += z2_slope;
3089      r1_interp += r1_slope;   r2_interp += r2_slope;
3090      g1_interp += g1_slope;   g2_interp += g2_slope;
3091      b1_interp += b1_slope;   b2_interp += b2_slope;
3092      w1_interp += w1_slope;   w2_interp += w2_slope;
3093      s1_interp += s1_slope;   s2_interp += s2_slope;
3094      t1_interp += t1_slope;   t2_interp += t2_slope;
3095   }
3096
3097   // Now do the same thing for the top half of the triangle.
3098   // We only need to recompute the x2 line because it changes at the midpoint
3099   x2_slope = (p_max[0] - p_mid[0]) / (p_max[1] - p_mid[1]);
3100   z2_slope = (p_max[2] - p_mid[2]) / (p_max[1] - p_mid[1]);
3101   w2_slope = (p_max[3] - p_mid[3]) / (p_max[1] - p_mid[1]);
3102   r2_slope = (c_max[0] - c_mid[0]) / (p_max[1] - p_mid[1]);
3103   g2_slope = (c_max[1] - c_mid[1]) / (p_max[1] - p_mid[1]);
3104   b2_slope = (c_max[2] - c_mid[2]) / (p_max[1] - p_mid[1]);
3105   s2_slope = (t_max[0] - t_mid[0]) / (p_max[1] - p_mid[1]);
3106   t2_slope = (t_max[1] - t_mid[1]) / (p_max[1] - p_mid[1]);
3107
3108   t = (((float)y_mid) + 0.5 - p_mid[1]) / (p_max[1] - p_mid[1]);
3109   x2_interp = p_mid[0] + (p_max[0] - p_mid[0]) * t;
3110   z2_interp = p_mid[2] + (p_max[2] - p_mid[2]) * t;
3111   w2_interp = p_mid[3] + (p_max[3] - p_mid[3]) * t;
3112   r2_interp = c_mid[0] + (c_max[0] - c_mid[0]) * t;
3113   g2_interp = c_mid[1] + (c_max[1] - c_mid[1]) * t;
3114   b2_interp = c_mid[2] + (c_max[2] - c_mid[2]) * t;
3115   s2_interp = t_mid[0] + (t_max[0] - t_mid[0]) * t;
3116   t2_interp = t_mid[1] + (t_max[1] - t_mid[1]) * t;
3117
3118   // We've seen this loop before haven't we?
3119   // I'm using y_mid as the incrementer because it saves space and we don't need it anymore
3120   for (; y_mid <= y_max; y_mid++) {
3121      if (x1_interp < x2_interp) {
3122         x_start    = ((((int)x1_interp) + 0.5) >= x1_interp) ? (int)x1_interp : ((int)x1_interp) + 1;
3123         x_end      = ((((int)x2_interp) + 0.5) <  x2_interp) ? (int)x2_interp : ((int)x2_interp) - 1;
3124         z_delta_x  = (z2_interp - z1_interp) / (x2_interp - x1_interp);
3125         w_delta_x  = (w2_interp - w1_interp) / (x2_interp - x1_interp);
3126         r_delta_x  = (r2_interp - r1_interp) / (x2_interp - x1_interp);
3127         g_delta_x  = (g2_interp - g1_interp) / (x2_interp - x1_interp);
3128         b_delta_x  = (b2_interp - b1_interp) / (x2_interp - x1_interp);
3129         s_delta_x  = (s2_interp - s1_interp) / (x2_interp - x1_interp);
3130         t_delta_x  = (t2_interp - t1_interp) / (x2_interp - x1_interp);
3131         t          = (x_start + 0.5 - x1_interp) / (x2_interp - x1_interp);
3132         z_interp_x = z1_interp + (z2_interp - z1_interp) * t;
3133         w_interp_x = w1_interp + (w2_interp - w1_interp) * t;
3134         r_interp_x = r1_interp + (r2_interp - r1_interp) * t;
3135         g_interp_x = g1_interp + (g2_interp - g1_interp) * t;
3136         b_interp_x = b1_interp + (b2_interp - b1_interp) * t;
3137         s_interp_x = s1_interp + (s2_interp - s1_interp) * t;
3138         t_interp_x = t1_interp + (t2_interp - t1_interp) * t;
3139
3140      } else {
3141         x_start    = ((((int)x2_interp) + 0.5) >= x2_interp) ? (int)x2_interp : ((int)x2_interp) + 1;
3142         x_end      = ((((int)x1_interp) + 0.5) <  x1_interp) ? (int)x1_interp : ((int)x1_interp) - 1;
3143         z_delta_x  = (z1_interp - z2_interp) / (x1_interp - x2_interp);
3144         w_delta_x  = (w1_interp - w2_interp) / (x1_interp - x2_interp);
3145         r_delta_x  = (r1_interp - r2_interp) / (x1_interp - x2_interp);
3146         g_delta_x  = (g1_interp - g2_interp) / (x1_interp - x2_interp);
3147         b_delta_x  = (b1_interp - b2_interp) / (x1_interp - x2_interp);
3148         s_delta_x  = (s1_interp - s2_interp) / (x1_interp - x2_interp);
3149         t_delta_x  = (t1_interp - t2_interp) / (x1_interp - x2_interp);
3150         t          = (x_start + 0.5 - x2_interp) / (x1_interp - x2_interp);
3151         z_interp_x = z2_interp + (z1_interp - z2_interp) * t;
3152         w_interp_x = w2_interp + (w1_interp - w2_interp) * t;
3153         r_interp_x = r2_interp + (r1_interp - r2_interp) * t;
3154         g_interp_x = g2_interp + (g1_interp - g2_interp) * t;
3155         b_interp_x = b2_interp + (b1_interp - b2_interp) * t;
3156         s_interp_x = s2_interp + (s1_interp - s2_interp) * t;
3157         t_interp_x = t2_interp + (t1_interp - t2_interp) * t;
3158      }
3159
3160      // Pass the horizontal line to the filler, this could be put in the routine
3161      // then interpolate for the next values of x and z
3162      FillSmoothTexPCHorizontalLine( prOptions,
3163         x_start, x_end, y_mid, z_interp_x, z_delta_x, w_interp_x, w_delta_x,
3164         r_interp_x, r_delta_x, g_interp_x, g_delta_x, b_interp_x, b_delta_x,
3165         s_interp_x, s_delta_x, t_interp_x, t_delta_x);
3166      x1_interp += x1_slope;   z1_interp += z1_slope;
3167      x2_interp += x2_slope;   z2_interp += z2_slope;
3168      r1_interp += r1_slope;   r2_interp += r2_slope;
3169      g1_interp += g1_slope;   g2_interp += g2_slope;
3170      b1_interp += b1_slope;   b2_interp += b2_slope;
3171      w1_interp += w1_slope;   w2_interp += w2_slope;
3172      s1_interp += s1_slope;   s2_interp += s2_slope;
3173      t1_interp += t1_slope;   t2_interp += t2_slope;
3174   }
3175}
3176
3177void hng64_state::drawShaded( struct polygon *p)
3178{
3179   // The perspective-correct texture divide...
3180   // !!! There is a very good chance the HNG64 hardware does not do perspective-correct texture-mapping !!!
3181   int j;
3182   for (j = 0; j < p->n; j++)
3183   {
3184      p->vert[j].clipCoords[3] = 1.0f / p->vert[j].clipCoords[3];
3185      p->vert[j].light[0]      = p->vert[j].light[0]     * p->vert[j].clipCoords[3];
3186      p->vert[j].light[1]      = p->vert[j].light[1]     * p->vert[j].clipCoords[3];
3187      p->vert[j].light[2]      = p->vert[j].light[2]     * p->vert[j].clipCoords[3];
3188      p->vert[j].texCoords[0]  = p->vert[j].texCoords[0] * p->vert[j].clipCoords[3];
3189      p->vert[j].texCoords[1]  = p->vert[j].texCoords[1] * p->vert[j].clipCoords[3];
3190   }
3191
3192   // Set up the struct that will pass the polygon's options around.
3193   polygonRasterOptions prOptions;
3194   prOptions.texType = p->texType;
3195   prOptions.texIndex = p->texIndex;
3196   prOptions.palOffset = p->palOffset;
3197   prOptions.palPageSize = p->palPageSize;
3198   prOptions.debugColor = p->debugColor;
3199   prOptions.texPageSmall = p->texPageSmall;
3200   prOptions.texPageHorizOffset = p->texPageHorizOffset;
3201   prOptions.texPageVertOffset = p->texPageVertOffset;
3202
3203   for (j = 1; j < p->n-1; j++)
3204   {
3205      RasterizeTriangle_SMOOTH_TEX_PC(
3206                              p->vert[0].clipCoords, p->vert[j].clipCoords, p->vert[j+1].clipCoords,
3207                              p->vert[0].light,      p->vert[j].light,      p->vert[j+1].light,
3208                              p->vert[0].texCoords,  p->vert[j].texCoords,  p->vert[j+1].texCoords,
3209                              prOptions);
3210   }
3211}
trunk/src/mame/video/hng64_3d.c
r0r244701
1/* Hyper NeoGeo 64 - 3D bits */
2
3// todo, use poly.c
4
5#include "includes/hng64.h"
6
7
8
9// Hardware calls these '3d buffers'
10//   They're only read during the startup check of fatfurwa.  Z-buffer memory?  Front buffer, back buffer?
11//   They're definitely mirrored in the startup test, according to ElSemi
12//   30100000-3011ffff is framebuffer A0
13//   30120000-3013ffff is framebuffer A1
14//   30140000-3015ffff is ZBuffer A
15
16READ32_MEMBER(hng64_state::hng64_3d_1_r)
17{
18   return m_3d_1[offset];
19}
20
21WRITE32_MEMBER(hng64_state::hng64_3d_1_w)
22{
23   COMBINE_DATA (&m_3d_1[offset]);
24}
25
26READ32_MEMBER(hng64_state::hng64_3d_2_r)
27{
28   return m_3d_2[offset];
29}
30
31WRITE32_MEMBER(hng64_state::hng64_3d_2_w)
32{
33   COMBINE_DATA (&m_3d_2[offset]);
34}
35
36// The 3d 'display list'
37WRITE16_MEMBER(hng64_state::dl_w)
38{
39   COMBINE_DATA(&m_dl[offset]);
40}
41
42
43
44
45/* TODO: different param for both Samurai games, less FIFO to process? */
46WRITE32_MEMBER(hng64_state::dl_upload_w)
47{
48   // this is written after the game uploads 16 packets, each 32 bytes long (2x 16 words?)
49   // we're assuming it to be a 'send to 3d hardware' trigger.
50   // this can be called multiple times per frame (at least 2, as long as it gets the expected interrupt / status flags)
51
52   for(int packetStart=0;packetStart<0x200;packetStart+=32)
53   {
54      // Send it off to the 3d subsystem.
55      hng64_command3d( &m_dl[packetStart/2] );
56   }
57
58   machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(0x200*8), timer_expired_delegate(FUNC(hng64_state::hng64_3dfifo_processed),this));
59}
60
61TIMER_CALLBACK_MEMBER(hng64_state::hng64_3dfifo_processed )
62{
63// ...
64   m_set_irq(0x0008);
65}
66
67
68/* Note: Samurai Shodown games never calls bit 1, so it can't be framebuffer clear. It also calls bit 3 at start-up, meaning unknown */
69WRITE32_MEMBER(hng64_state::dl_control_w) // This handles framebuffers
70{
71//   printf("dl_control_w %08x %08x\n", data, mem_mask);
72
73   //if(data & 2) // swap buffers
74   //{
75   //  clear3d();
76   //}
77
78//  printf("%02x\n",data);
79
80//  if(data & 1) // process DMA from 3d FIFO to framebuffer
81
82//  if(data & 4) // reset buffer count
83}
84
85
86
87
88////////////////////
89// 3d 'Functions' //
90////////////////////
91
92void hng64_state::printPacket(const UINT16* packet, int hex)
93{
94   if (hex)
95   {
96      printf("Packet : %04x %04x  2:%04x %04x  4:%04x %04x  6:%04x %04x  8:%04x %04x  10:%04x %04x  12:%04x %04x  14:%04x %04x\n",
97            packet[0],  packet[1],
98            packet[2],  packet[3],
99            packet[4],  packet[5],
100            packet[6],  packet[7],
101            packet[8],  packet[9],
102            packet[10], packet[11],
103            packet[12], packet[13],
104            packet[14], packet[15]);
105   }
106   else
107   {
108      printf("Packet : %04x %3.4f  2:%3.4f %3.4f  4:%3.4f %3.4f  6:%3.4f %3.4f  8:%3.4f %3.4f  10:%3.4f %3.4f  12:%3.4f %3.4f  14:%3.4f %3.4f\n",
109            packet[0],            uToF(packet[1] )*128,
110            uToF(packet[2] )*128, uToF(packet[3] )*128,
111            uToF(packet[4] )*128, uToF(packet[5] )*128,
112            uToF(packet[6] )*128, uToF(packet[7] )*128,
113            uToF(packet[8] )*128, uToF(packet[9] )*128,
114            uToF(packet[10])*128, uToF(packet[11])*128,
115            uToF(packet[12])*128, uToF(packet[13])*128,
116            uToF(packet[14])*128, uToF(packet[15])*128);
117   }
118}
119
120// Operation 0001
121// Camera transformation.
122void hng64_state::setCameraTransformation(const UINT16* packet)
123{
124   float *cameraMatrix = m_cameraMatrix;
125
126   /*//////////////
127   // PACKET FORMAT
128   // [0]  - 0001 ... ID
129   // [1]  - xxxx ... Extrinsic camera matrix
130   // [2]  - xxxx ... Extrinsic camera matrix
131   // [3]  - xxxx ... Extrinsic camera matrix
132   // [4]  - xxxx ... Extrinsic camera matrix
133   // [5]  - xxxx ... Extrinsic camera matrix
134   // [6]  - xxxx ... Extrinsic camera matrix
135   // [7]  - xxxx ... Extrinsic camera matrix
136   // [8]  - xxxx ... Extrinsic camera matrix
137   // [9]  - xxxx ... Extrinsic camera matrix
138   // [10] - xxxx ... Extrinsic camera matrix
139   // [11] - xxxx ... Extrinsic camera matrix
140   // [12] - xxxx ... Extrinsic camera matrix
141   // [13] - ???? ... ? Flips per-frame during fatfurwa 'HNG64'
142   // [14] - ???? ... ? Could be some floating-point values during buriki 'door run'
143   // [15] - ???? ... ? Same as 13 & 14
144   ////////////*/
145   // CAMERA TRANSFORMATION MATRIX
146   cameraMatrix[0]  = uToF(packet[1]);
147   cameraMatrix[4]  = uToF(packet[2]);
148   cameraMatrix[8]  = uToF(packet[3]);
149   cameraMatrix[3]  = 0.0f;
150
151   cameraMatrix[1]  = uToF(packet[4]);
152   cameraMatrix[5]  = uToF(packet[5]);
153   cameraMatrix[9]  = uToF(packet[6]);
154   cameraMatrix[7]  = 0.0f;
155
156   cameraMatrix[2]  = uToF(packet[7]);
157   cameraMatrix[6]  = uToF(packet[8]);
158   cameraMatrix[10] = uToF(packet[9]);
159   cameraMatrix[11] = 0.0f;
160
161   cameraMatrix[12] = uToF(packet[10]);
162   cameraMatrix[13] = uToF(packet[11]);
163   cameraMatrix[14] = uToF(packet[12]);
164   cameraMatrix[15] = 1.0f;
165}
166
167// Operation 0010
168// Lighting information
169void hng64_state::setLighting(const UINT16* packet)
170{
171   float *lightVector = m_lightVector;
172
173   /*//////////////
174   // PACKET FORMAT
175   // [0]  - 0010 ... ID
176   // [1]  - ???? ... ? Always zero
177   // [2]  - ???? ... ? Always zero
178   // [3]  - xxxx ... X light vector direction
179   // [4]  - xxxx ... Y light vector direction
180   // [5]  - xxxx ... Z light vector direction
181   // [6]  - ???? ... ? Seems to be another light vector ?
182   // [7]  - ???? ... ? Seems to be another light vector ?
183   // [8]  - ???? ... ? Seems to be another light vector ?
184   // [9]  - xxxx ... Strength according to sams64_2 [0000,01ff]
185   // [10] - ???? ... ? Used in fatfurwa
186   // [11] - ???? ... ? Used in fatfurwa
187   // [12] - ???? ... ? Used in fatfurwa
188   // [13] - ???? ... ? Used in fatfurwa
189   // [14] - ???? ... ? Used in fatfurwa
190   // [15] - ???? ... ? Used in fatfurwa
191   ////////////*/
192   if (packet[1] != 0x0000) printf("ZOMG!  packet[1] in setLighting function is non-zero!\n");
193   if (packet[2] != 0x0000) printf("ZOMG!  packet[2] in setLighting function is non-zero!\n");
194
195   lightVector[0] = uToF(packet[3]);
196   lightVector[1] = uToF(packet[4]);
197   lightVector[2] = uToF(packet[5]);
198   m_lightStrength = uToF(packet[9]);
199}
200
201// Operation 0011
202// Palette / Model flags?
203void hng64_state::set3dFlags(const UINT16* packet)
204{
205   /*//////////////
206   // PACKET FORMAT
207   // [0]  - 0011 ... ID
208   // [1]  - ???? ...
209   // [2]  - ???? ...
210   // [3]  - ???? ...
211   // [4]  - ???? ...
212   // [5]  - ???? ...
213   // [6]  - ???? ...
214   // [7]  - ???? ...
215   // [8]  - xx?? ... Palette offset & ??
216   // [9]  - ???? ... ? Very much used - seem to bounce around when characters are on screen
217   // [10] - ???? ... ? ''  ''
218   // [11] - ???? ... ? ''  ''
219   // [12] - ???? ... ? ''  ''
220   // [13] - ???? ... ? ''  ''
221   // [14] - ???? ... ? ''  ''
222   // [15] - ???? ... ? ''  ''
223   ////////////*/
224   m_paletteState3d = (packet[8] & 0xff00) >> 8;
225}
226
227// Operation 0012
228// Projection Matrix.
229void hng64_state::setCameraProjectionMatrix(const UINT16* packet)
230{
231   float *projectionMatrix = m_projectionMatrix;
232
233   /*//////////////
234   // PACKET FORMAT
235   // [0]  - 0012 ... ID
236   // [1]  - ???? ... ? Contains a value in buriki's 'how to play' - probably a projection window/offset.
237   // [2]  - ???? ... ? Contains a value in buriki's 'how to play' - probably a projection window/offset.
238   // [3]  - ???? ... ? Contains a value
239   // [4]  - xxxx ... Camera projection near scale
240   // [5]  - xxxx ... Camera projection near height(?)
241   // [6]  - xxxx ... Camera projection near width(?)
242   // [7]  - xxxx ... Camera projection far scale
243   // [8]  - xxxx ... Camera projection far height(?)
244   // [9]  - xxxx ... Camera projection far width(?)
245   // [10] - xxxx ... Camera projection right
246   // [11] - xxxx ... Camera projection left
247   // [12] - xxxx ... Camera projection top
248   // [13] - xxxx ... Camera projection bottom
249   // [14] - ???? ... ? Gets data during buriki door-run
250   // [15] - ???? ... ? Gets data during buriki door-run
251   ////////////*/
252
253   // Heisted from GLFrustum - 6 parameters...
254   float left, right, top, bottom, near_, far_;
255
256   left    = uToF(packet[11]);
257   right   = uToF(packet[10]);
258   top     = uToF(packet[12]);
259   bottom  = uToF(packet[13]);
260   near_   = uToF(packet[6]) + (uToF(packet[6]) * uToF(packet[4]));
261   far_    = uToF(packet[9]) + (uToF(packet[9]) * uToF(packet[7]));
262   // (note are likely not 100% correct - I'm not using one of the parameters)
263
264   projectionMatrix[0]  = (2.0f*near_)/(right-left);
265   projectionMatrix[1]  = 0.0f;
266   projectionMatrix[2]  = 0.0f;
267   projectionMatrix[3]  = 0.0f;
268
269   projectionMatrix[4]  = 0.0f;
270   projectionMatrix[5]  = (2.0f*near_)/(top-bottom);
271   projectionMatrix[6]  = 0.0f;
272   projectionMatrix[7]  = 0.0f;
273
274   projectionMatrix[8]  = (right+left)/(right-left);
275   projectionMatrix[9]  = (top+bottom)/(top-bottom);
276   projectionMatrix[10] = -((far_+near_)/(far_-near_));
277   projectionMatrix[11] = -1.0f;
278
279   projectionMatrix[12] = 0.0f;
280   projectionMatrix[13] = 0.0f;
281   projectionMatrix[14] = -((2.0f*far_*near_)/(far_-near_));
282   projectionMatrix[15] = 0.0f;
283}
284
285// Operation 0100
286// Polygon rasterization.
287void hng64_state::recoverPolygonBlock(const UINT16* packet, struct polygon* polys, int* numPolys)
288{
289   /*//////////////
290   // PACKET FORMAT
291   // [0]  - 0100 ... ID
292   // [1]  - ?--- ... Flags [?000 = ???
293   //                        0?00 = ???
294   //                        00?0 = ???
295   //                        000? = ???]
296   // [1]  - -?-- ... Flags [?000 = ???
297   //                        0?00 = ???
298   //                        00?0 = ???
299   //                        000x = Dynamic palette bit]
300   // [1]  - --?- ... Flags [?000 = ???
301   //                        0?00 = ???
302   //                        00?0 = ???
303   //                        000? = ???]
304   // [1]  - ---? ... Flags [x000 = Apply lighting bit
305   //                        0?00 = ???
306   //                        00?0 = ???
307   //                        000? = ???]
308   // [2]  - xxxx ... offset into ROM
309   // [3]  - xxxx ... offset into ROM
310   // [4]  - xxxx ... Transformation matrix
311   // [5]  - xxxx ... Transformation matrix
312   // [6]  - xxxx ... Transformation matrix
313   // [7]  - xxxx ... Transformation matrix
314   // [8]  - xxxx ... Transformation matrix
315   // [9]  - xxxx ... Transformation matrix
316   // [10] - xxxx ... Transformation matrix
317   // [11] - xxxx ... Transformation matrix
318   // [12] - xxxx ... Transformation matrix
319   // [13] - xxxx ... Transformation matrix
320   // [14] - xxxx ... Transformation matrix
321   // [15] - xxxx ... Transformation matrix
322   ////////////*/
323
324
325
326   float objectMatrix[16];
327   setIdentity(objectMatrix);
328   /////////////////
329   // HEADER INFO //
330   /////////////////
331   // THE OBJECT TRANSFORMATION MATRIX
332   objectMatrix[8] = uToF(packet[7]);
333   objectMatrix[4] = uToF(packet[8]);
334   objectMatrix[0] = uToF(packet[9]);
335   objectMatrix[3] = 0.0f;
336
337   objectMatrix[9] = uToF(packet[10]);
338   objectMatrix[5] = uToF(packet[11]);
339   objectMatrix[1] = uToF(packet[12]);
340   objectMatrix[7] = 0.0f;
341
342   objectMatrix[10] = uToF(packet[13]);
343   objectMatrix[6 ] = uToF(packet[14]);
344   objectMatrix[2 ] = uToF(packet[15]);
345   objectMatrix[11] = 0.0f;
346
347   objectMatrix[12] = uToF(packet[4]);
348   objectMatrix[13] = uToF(packet[5]);
349   objectMatrix[14] = uToF(packet[6]);
350   objectMatrix[15] = 1.0f;
351
352   UINT32 size[4];
353   UINT32 address[4];
354   UINT32 megaOffset;
355   float eyeCoords[4];     // ObjectCoords transformed by the modelViewMatrix
356//  float clipCoords[4];    // EyeCoords transformed by the projectionMatrix
357   float ndCoords[4];      // Normalized device coordinates/clipCoordinates (x/w, y/w, z/w)
358   float windowCoords[4];  // Mapped ndCoordinates to screen space
359   float cullRay[4];
360   struct polygon lastPoly = { 0 };
361   const rectangle &visarea = m_screen->visible_area();
362
363
364   //////////////////////////////////////////////////////////
365   // EXTRACT DATA FROM THE ADDRESS POINTED TO IN THE FILE //
366   //////////////////////////////////////////////////////////
367   /*//////////////////////////////////////////////
368   // DIRECTLY-POINTED-TO FORMAT (7 words x 3 ROMs)
369   // [0]  - lower word of sub-address 1
370   // [1]  - lower word of sub-address 2
371   // [2]  - upper word of all sub-addresses
372   // [3]  - lower word of sub-address 3
373   // [4]  - lower word of sub-address 4
374   // [5]  - ???? always 0 ????
375   // [6]  - number of chunks in sub-address 1 block
376   // [7]  - number of chunks in sub-address 2 block
377   // [8]  - ???? always 0 ????
378   // [9]  - number of chunks in sub-address 3 block
379   // [10] - number of chunks in sub-address 4 block
380   // [11] - ? definitely used.
381   // [12] - ? definitely used.
382   // [13] - ? definitely used.
383   // [14] - ? definitely used.
384   // [15] - ???? always 0 ????
385   // [16] - ???? always 0 ????
386   // [17] - ???? always 0 ????
387   // [18] - ???? always 0 ????
388   // [19] - ???? always 0 ????
389   // [20] - ???? always 0 ????
390   //////////////////////////////////////////////*/
391
392   // 3d ROM Offset
393   UINT16* threeDRoms = m_vertsrom;
394   UINT32  threeDOffset = (((UINT32)packet[2]) << 16) | ((UINT32)packet[3]);
395   UINT16* threeDPointer = &threeDRoms[threeDOffset * 3];
396
397   if (threeDOffset >= m_vertsrom_size)
398   {
399      printf("Strange geometry packet: (ignoring)\n");
400      printPacket(packet, 1);
401      return;
402   }
403
404#if 0
405   // Debug - ajg
406   printf("%08x : ", threeDOffset*3*2);
407   for (int k = 0; k < 7*3; k++)
408   {
409      printf("%04x ", threeDPointer[k]);
410      if ((k % 3) == 2) printf(" ");
411   }
412   printf("\n");
413#endif
414
415   // There are 4 hunks per address.
416   address[0] = threeDPointer[0];
417   address[1] = threeDPointer[1];
418   megaOffset = threeDPointer[2];
419
420   address[2] = threeDPointer[3];
421   address[3] = threeDPointer[4];
422   if (threeDPointer[5] != 0x0000) printf("ZOMG!  3dPointer[5] is non-zero!\n");
423
424   size[0]    = threeDPointer[6];
425   size[1]    = threeDPointer[7];
426   if (threeDPointer[8] != 0x0000) printf("ZOMG!  3dPointer[8] is non-zero!\n");
427
428   size[2]    = threeDPointer[9];
429   size[3]    = threeDPointer[10];
430   /*           ????         [11]; Used. */
431
432   /*           ????         [12]; Used. */
433   /*           ????         [13]; Used. */
434   /*           ????         [14]; Used. */
435
436   if (threeDPointer[15] != 0x0000) printf("ZOMG!  3dPointer[15] is non-zero!\n");
437   if (threeDPointer[16] != 0x0000) printf("ZOMG!  3dPointer[16] is non-zero!\n");
438   if (threeDPointer[17] != 0x0000) printf("ZOMG!  3dPointer[17] is non-zero!\n");
439
440   if (threeDPointer[18] != 0x0000) printf("ZOMG!  3dPointer[18] is non-zero!\n");
441   if (threeDPointer[19] != 0x0000) printf("ZOMG!  3dPointer[19] is non-zero!\n");
442   if (threeDPointer[20] != 0x0000) printf("ZOMG!  3dPointer[20] is non-zero!\n");
443
444   /* Concatenate the megaOffset with the addresses */
445   address[0] |= (megaOffset << 16);
446   address[1] |= (megaOffset << 16);
447   address[2] |= (megaOffset << 16);
448   address[3] |= (megaOffset << 16);
449
450   // Debug - ajg
451   //UINT32 tdColor = 0xff000000;
452   //if (threeDPointer[14] & 0x0002) tdColor |= 0x00ff0000;
453   //if (threeDPointer[14] & 0x0001) tdColor |= 0x0000ff00;
454   //if (threeDPointer[14] & 0x0000) tdColor |= 0x000000ff;
455
456   /* For all 4 polygon chunks */
457   for (int k = 0; k < 4; k++)
458   {
459      UINT16* chunkOffset = &threeDRoms[address[k] * 3];
460      for (int l = 0; l < size[k]; l++)
461      {
462         ////////////////////////////////////////////
463         // GATHER A SINGLE TRIANGLE'S INFORMATION //
464         ////////////////////////////////////////////
465         // SINGLE POLY CHUNK FORMAT
466         // [0] ??-- - ???
467         // [0] --xx - Chunk type
468         //
469         // [1] ?--- - Flags [?000 = ???
470         //                   0?00 = ???
471         //                   00?0 = ???
472         //                   000x = low-res texture flag]
473         // [1] -x-- - Explicit 0x80 palette index.
474         // [1] --x- - Explicit 0x08 palette index.
475         // [1] ---x - Texture page (1024x1024 bytes)
476         //
477         // [2] x--- - Texture Flags [x000 = Uses 4x4 sub-texture pages?
478         //                           0?00 = ??? - differen sub-page size?  SNK logo in RoadEdge.  Always on in bbust2.
479         //                           00xx = Horizontal sub-texture page index]
480         // [2] -?-- - ??? - barely visible (thus far) in roadedge
481         // [2] --x- - Texture Flags [?000 = ???
482         //                           0xx0 = Vertical sub-texture page index.
483         //                           000? = ???]
484         // [2] ---? - ???
485         //////////////////////////
486         UINT8 chunkType = chunkOffset[0] & 0x00ff;
487
488         // Debug - ajg
489         if (chunkOffset[0] & 0xff00)
490         {
491            printf("Weird!  The top byte of the chunkType has a value %04x!\n", chunkOffset[0]);
492            continue;
493         }
494
495         // Debug - Colors polygons with certain flags bright blue! ajg
496         polys[*numPolys].debugColor = 0;
497         //polys[*numPolys].debugColor = tdColor;
498
499         // Debug - ajg
500         //printf("%d (%08x) : %04x %04x %04x\n", k, address[k]*3*2, chunkOffset[0], chunkOffset[1], chunkOffset[2]);
501         //break;
502
503         // TEXTURE
504         /* There may be more than just high & low res texture types, so I'm keeping texType as a UINT8. */
505         if (chunkOffset[1] & 0x1000) polys[*numPolys].texType = 0x1;
506         else                         polys[*numPolys].texType = 0x0;
507
508         polys[*numPolys].texPageSmall       = (chunkOffset[2] & 0x8000) >> 15;  // Just a guess.
509         polys[*numPolys].texPageHorizOffset = (chunkOffset[2] & 0x3000) >> 12;
510         polys[*numPolys].texPageVertOffset  = (chunkOffset[2] & 0x0060) >> 5;
511
512         polys[*numPolys].texIndex = chunkOffset[1] & 0x000f;
513
514
515         // PALETTE
516         polys[*numPolys].palOffset = 0;
517         polys[*numPolys].palPageSize = 0x100;
518
519         /* FIXME: This isn't correct.
520                   Buriki & Xrally need this line.  Roads Edge needs it removed.
521                   So instead we're looking for a bit that is on for XRally & Buriki, but noone else. */
522         if (m_3dregs[0x00/4] & 0x2000)
523         {
524            if (strcmp(machine().basename(), "roadedge"))
525               polys[*numPolys].palOffset += 0x800;
526         }
527
528         //UINT16 explicitPaletteValue0 = ((chunkOffset[?] & 0x????) >> ?) * 0x800;
529         UINT16 explicitPaletteValue1 = ((chunkOffset[1] & 0x0f00) >> 8) * 0x080;
530         UINT16 explicitPaletteValue2 = ((chunkOffset[1] & 0x00f0) >> 4) * 0x008;
531
532         // The presence of 0x00f0 *probably* sets 0x10-sized palette addressing.
533         if (explicitPaletteValue2) polys[*numPolys].palPageSize = 0x10;
534
535         // Apply the dynamic palette offset if its flag is set, otherwise stick with the fixed one
536         if ((packet[1] & 0x0100))
537         {
538            explicitPaletteValue1 = m_paletteState3d * 0x80;
539            explicitPaletteValue2 = 0;      // This is probably hiding somewhere in operation 0011
540         }
541
542         polys[*numPolys].palOffset += (explicitPaletteValue1 + explicitPaletteValue2);
543
544
545
546         UINT8 chunkLength = 0;
547         switch(chunkType)
548         {
549         /*/////////////////////////
550         // CHUNK TYPE BITS - These are very likely incorrect.
551         // x--- ---- - 1 = Has only 1 vertex (part of a triangle fan/strip)
552         // -x-- ---- -
553         // --x- ---- -
554         // ---x ---- -
555         // ---- x--- -
556         // ---- -x-- - 1 = Has per-vert UVs
557         // ---- --x- -
558         // ---- ---x - 1 = Has per-vert normals
559         /////////////////////////*/
560
561         // 33 word chunk, 3 vertices, per-vertex UVs & normals, per-face normal
562         case 0x05:  // 0000 0101
563         case 0x0f:  // 0000 1111
564            for (int m = 0; m < 3; m++)
565            {
566               polys[*numPolys].vert[m].worldCoords[0] = uToF(chunkOffset[3 + (9*m)]);
567               polys[*numPolys].vert[m].worldCoords[1] = uToF(chunkOffset[4 + (9*m)]);
568               polys[*numPolys].vert[m].worldCoords[2] = uToF(chunkOffset[5 + (9*m)]);
569               polys[*numPolys].vert[m].worldCoords[3] = 1.0f;
570               polys[*numPolys].n = 3;
571
572               // chunkOffset[6 + (9*m)] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select
573               polys[*numPolys].vert[m].texCoords[0] = uToF(chunkOffset[7 + (9*m)]);
574               polys[*numPolys].vert[m].texCoords[1] = uToF(chunkOffset[8 + (9*m)]);
575               polys[*numPolys].vert[m].texCoords[2] = 0.0f;
576               polys[*numPolys].vert[m].texCoords[3] = 1.0f;
577
578               polys[*numPolys].vert[m].normal[0] = uToF(chunkOffset[9  + (9*m)]);
579               polys[*numPolys].vert[m].normal[1] = uToF(chunkOffset[10 + (9*m)] );
580               polys[*numPolys].vert[m].normal[2] = uToF(chunkOffset[11 + (9*m)] );
581               polys[*numPolys].vert[m].normal[3] = 0.0f;
582            }
583
584            // Redundantly called, but it works...
585            polys[*numPolys].faceNormal[0] = uToF(chunkOffset[30]);
586            polys[*numPolys].faceNormal[1] = uToF(chunkOffset[31]);
587            polys[*numPolys].faceNormal[2] = uToF(chunkOffset[32]);
588            polys[*numPolys].faceNormal[3] = 0.0f;
589
590            chunkLength = 33;
591            break;
592
593
594         // 24 word chunk, 3 vertices, per-vertex UVs
595         case 0x04:  // 0000 0100
596         case 0x0e:  // 0000 1110
597         case 0x24:  // 0010 0100
598         case 0x2e:  // 0010 1110
599            for (int m = 0; m < 3; m++)
600            {
601               polys[*numPolys].vert[m].worldCoords[0] = uToF(chunkOffset[3 + (6*m)]);
602               polys[*numPolys].vert[m].worldCoords[1] = uToF(chunkOffset[4 + (6*m)]);
603               polys[*numPolys].vert[m].worldCoords[2] = uToF(chunkOffset[5 + (6*m)]);
604               polys[*numPolys].vert[m].worldCoords[3] = 1.0f;
605               polys[*numPolys].n = 3;
606
607               // chunkOffset[6 + (6*m)] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select
608               polys[*numPolys].vert[m].texCoords[0] = uToF(chunkOffset[7 + (6*m)]);
609               polys[*numPolys].vert[m].texCoords[1] = uToF(chunkOffset[8 + (6*m)]);
610               polys[*numPolys].vert[m].texCoords[2] = 0.0f;
611               polys[*numPolys].vert[m].texCoords[3] = 1.0f;
612
613               polys[*numPolys].vert[m].normal[0] = uToF(chunkOffset[21]);
614               polys[*numPolys].vert[m].normal[1] = uToF(chunkOffset[22]);
615               polys[*numPolys].vert[m].normal[2] = uToF(chunkOffset[23]);
616               polys[*numPolys].vert[m].normal[3] = 0.0f;
617            }
618
619            // Redundantly called, but it works...
620            polys[*numPolys].faceNormal[0] = polys[*numPolys].vert[2].normal[0];
621            polys[*numPolys].faceNormal[1] = polys[*numPolys].vert[2].normal[1];
622            polys[*numPolys].faceNormal[2] = polys[*numPolys].vert[2].normal[2];
623            polys[*numPolys].faceNormal[3] = 0.0f;
624
625            chunkLength = 24;
626            break;
627
628
629         // 15 word chunk, 1 vertex, per-vertex UVs & normals, face normal
630         case 0x87:  // 1000 0111
631         case 0x97:  // 1001 0111
632         case 0xd7:  // 1101 0111
633         case 0xc7:  // 1100 0111
634            // Copy over the proper vertices from the previous triangle...
635            memcpy(&polys[*numPolys].vert[1], &lastPoly.vert[0], sizeof(struct polyVert));
636            memcpy(&polys[*numPolys].vert[2], &lastPoly.vert[2], sizeof(struct polyVert));
637
638            // Fill in the appropriate data...
639            polys[*numPolys].vert[0].worldCoords[0] = uToF(chunkOffset[3]);
640            polys[*numPolys].vert[0].worldCoords[1] = uToF(chunkOffset[4]);
641            polys[*numPolys].vert[0].worldCoords[2] = uToF(chunkOffset[5]);
642            polys[*numPolys].vert[0].worldCoords[3] = 1.0f;
643            polys[*numPolys].n = 3;
644
645            // chunkOffset[6] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select
646            polys[*numPolys].vert[0].texCoords[0] = uToF(chunkOffset[7]);
647            polys[*numPolys].vert[0].texCoords[1] = uToF(chunkOffset[8]);
648            polys[*numPolys].vert[0].texCoords[2] = 0.0f;
649            polys[*numPolys].vert[0].texCoords[3] = 1.0f;
650
651            polys[*numPolys].vert[0].normal[0] = uToF(chunkOffset[9]);
652            polys[*numPolys].vert[0].normal[1] = uToF(chunkOffset[10]);
653            polys[*numPolys].vert[0].normal[2] = uToF(chunkOffset[11]);
654            polys[*numPolys].vert[0].normal[3] = 0.0f;
655
656            polys[*numPolys].faceNormal[0] = uToF(chunkOffset[12]);
657            polys[*numPolys].faceNormal[1] = uToF(chunkOffset[13]);
658            polys[*numPolys].faceNormal[2] = uToF(chunkOffset[14]);
659            polys[*numPolys].faceNormal[3] = 0.0f;
660
661            chunkLength = 15;
662            break;
663
664
665         // 12 word chunk, 1 vertex, per-vertex UVs
666         case 0x86:  // 1000 0110
667         case 0x96:  // 1001 0110
668         case 0xb6:  // 1011 0110
669         case 0xc6:  // 1100 0110
670         case 0xd6:  // 1101 0110
671            // Copy over the proper vertices from the previous triangle...
672            memcpy(&polys[*numPolys].vert[1], &lastPoly.vert[0], sizeof(struct polyVert));
673            memcpy(&polys[*numPolys].vert[2], &lastPoly.vert[2], sizeof(struct polyVert));
674
675            polys[*numPolys].vert[0].worldCoords[0] = uToF(chunkOffset[3]);
676            polys[*numPolys].vert[0].worldCoords[1] = uToF(chunkOffset[4]);
677            polys[*numPolys].vert[0].worldCoords[2] = uToF(chunkOffset[5]);
678            polys[*numPolys].vert[0].worldCoords[3] = 1.0f;
679            polys[*numPolys].n = 3;
680
681            // chunkOffset[6] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select
682            polys[*numPolys].vert[0].texCoords[0] = uToF(chunkOffset[7]);
683            polys[*numPolys].vert[0].texCoords[1] = uToF(chunkOffset[8]);
684            polys[*numPolys].vert[0].texCoords[2] = 0.0f;
685            polys[*numPolys].vert[0].texCoords[3] = 1.0f;
686
687            // This normal could be right, but I'm not entirely sure - there is no normal in the 18 bytes!
688            polys[*numPolys].vert[0].normal[0] = lastPoly.faceNormal[0];
689            polys[*numPolys].vert[0].normal[1] = lastPoly.faceNormal[1];
690            polys[*numPolys].vert[0].normal[2] = lastPoly.faceNormal[2];
691            polys[*numPolys].vert[0].normal[3] = lastPoly.faceNormal[3];
692
693            polys[*numPolys].faceNormal[0] = lastPoly.faceNormal[0];
694            polys[*numPolys].faceNormal[1] = lastPoly.faceNormal[1];
695            polys[*numPolys].faceNormal[2] = lastPoly.faceNormal[2];
696            polys[*numPolys].faceNormal[3] = lastPoly.faceNormal[3];
697
698            // TODO: I'm not reading 3 necessary words here (maybe face normal) !!!
699
700#if 0
701            // DEBUG
702            printf("0x?6 : %08x (%d/%d)\n", address[k]*3*2, l, size[k]-1);
703            for (int m = 0; m < 13; m++)
704               printf("%04x ", chunkOffset[m]);
705            printf("\n");
706
707            for (int m = 0; m < 13; m++)
708               printf("%3.4f ", uToF(chunkOffset[m]));
709            printf("\n\n");
710#endif
711
712            chunkLength = 12;
713            break;
714
715         default:
716            printf("UNKNOWN geometry CHUNK TYPE : %02x\n", chunkType);
717            chunkLength = 0;
718            break;
719         }
720
721         polys[*numPolys].visible = 1;
722
723         // Backup the last polygon (for triangle fans [strips?])
724         memcpy(&lastPoly, &polys[*numPolys], sizeof(struct polygon));
725
726
727         ////////////////////////////////////
728         // Project and clip               //
729         ////////////////////////////////////
730         // Perform the world transformations...
731         // !! Can eliminate this step with a matrix stack (maybe necessary?) !!
732         setIdentity(m_modelViewMatrix);
733         if (m_mcu_type != SAMSHO_MCU)
734         {
735            // The sams64 games transform the geometry in front of a stationary camera.
736            // This is fine in sams64_2, since it never calls the 'camera transformation' function
737            // (thus using the identity matrix for this transform), but sams64 calls the
738            // camera transformation function with rotation values.
739            // It remains to be seen what those might do...
740            matmul4(m_modelViewMatrix, m_modelViewMatrix, m_cameraMatrix);
741         }
742         matmul4(m_modelViewMatrix, m_modelViewMatrix, objectMatrix);
743
744         // LIGHTING
745         if (packet[1] & 0x0008 && m_lightStrength > 0.0f)
746         {
747            for (int v = 0; v < 3; v++)
748            {
749               float transformedNormal[4];
750               vecmatmul4(transformedNormal, objectMatrix, polys[*numPolys].vert[v].normal);
751               normalize(transformedNormal);
752               normalize(m_lightVector);
753
754               float intensity = vecDotProduct(transformedNormal, m_lightVector) * -1.0f;
755               intensity = (intensity <= 0.0f) ? (0.0f) : (intensity);
756               intensity *= m_lightStrength * 128.0f;    // Turns 0x0100 into 1.0
757               intensity *= 128.0;                     // Maps intensity to the range [0.0, 2.0]
758               if (intensity >= 255.0f) intensity = 255.0f;
759
760               polys[*numPolys].vert[v].light[0] = intensity;
761               polys[*numPolys].vert[v].light[1] = intensity;
762               polys[*numPolys].vert[v].light[2] = intensity;
763            }
764         }
765         else
766         {
767            // Just clear out the light values
768            for (int v = 0; v < 3; v++)
769            {
770               polys[*numPolys].vert[v].light[0] = 0;
771               polys[*numPolys].vert[v].light[1] = 0;
772               polys[*numPolys].vert[v].light[2] = 0;
773            }
774         }
775
776
777         // BACKFACE CULL //
778         // EMPIRICAL EVIDENCE SEEMS TO SHOW THE HNG64 HARDWARE DOES NOT BACKFACE CULL //
779#if 0
780         float cullRay[4];
781         float cullNorm[4];
782
783         // Cast a ray out of the camera towards the polygon's point in eyespace.
784         vecmatmul4(cullRay, modelViewMatrix, polys[*numPolys].vert[0].worldCoords);
785         normalize(cullRay);
786         // Dot product that with the normal to see if you're negative...
787         vecmatmul4(cullNorm, modelViewMatrix, polys[*numPolys].faceNormal);
788
789         float result = vecDotProduct(cullRay, cullNorm);
790
791         if (result < 0.0f)
792            polys[*numPolys].visible = 1;
793         else
794            polys[*numPolys].visible = 0;
795#endif
796
797
798         // BEHIND-THE-CAMERA CULL //
799         vecmatmul4(cullRay, m_modelViewMatrix, polys[*numPolys].vert[0].worldCoords);
800         if (cullRay[2] > 0.0f)              // Camera is pointing down -Z
801         {
802            polys[*numPolys].visible = 0;
803         }
804
805
806         // TRANSFORM THE TRIANGLE INTO HOMOGENEOUS SCREEN SPACE //
807         if (polys[*numPolys].visible)
808         {
809            for (int m = 0; m < polys[*numPolys].n; m++)
810            {
811               // Transform and project the vertex into pre-divided homogeneous coordinates...
812               vecmatmul4(eyeCoords, m_modelViewMatrix, polys[*numPolys].vert[m].worldCoords);
813               vecmatmul4(polys[*numPolys].vert[m].clipCoords, m_projectionMatrix, eyeCoords);
814            }
815
816            if (polys[*numPolys].visible)
817            {
818               // Clip the triangles to the view frustum...
819               performFrustumClip(&polys[*numPolys]);
820
821               for (int m = 0; m < polys[*numPolys].n; m++)
822               {
823                  // Convert into normalized device coordinates...
824                  ndCoords[0] = polys[*numPolys].vert[m].clipCoords[0] / polys[*numPolys].vert[m].clipCoords[3];
825                  ndCoords[1] = polys[*numPolys].vert[m].clipCoords[1] / polys[*numPolys].vert[m].clipCoords[3];
826                  ndCoords[2] = polys[*numPolys].vert[m].clipCoords[2] / polys[*numPolys].vert[m].clipCoords[3];
827                  ndCoords[3] = polys[*numPolys].vert[m].clipCoords[3];
828
829                  // Final pixel values are garnered here :
830                  windowCoords[0] = (ndCoords[0]+1.0f) * ((float)(visarea.max_x) / 2.0f) + 0.0f;
831                  windowCoords[1] = (ndCoords[1]+1.0f) * ((float)(visarea.max_y) / 2.0f) + 0.0f;
832                  windowCoords[2] = (ndCoords[2]+1.0f) * 0.5f;
833
834                  windowCoords[1] = (float)visarea.max_y - windowCoords[1];       // Flip Y
835
836                  // Store the points in a list for later use...
837                  polys[*numPolys].vert[m].clipCoords[0] = windowCoords[0];
838                  polys[*numPolys].vert[m].clipCoords[1] = windowCoords[1];
839                  polys[*numPolys].vert[m].clipCoords[2] = windowCoords[2];
840                  polys[*numPolys].vert[m].clipCoords[3] = ndCoords[3];
841               }
842            }
843         }
844
845         // Advance to the next polygon chunk...
846         chunkOffset += chunkLength;
847
848         (*numPolys)++;
849      }
850   }
851}
852
853void hng64_state::hng64_command3d(const UINT16* packet)
854{
855
856   /* A temporary place to put some polygons.  This will optimize away if the compiler's any good. */
857   int numPolys = 0;
858   dynamic_array<polygon> polys(1024*5);
859
860   //printf("packet type : %04x %04x|%04x %04x|%04x %04x|%04x %04x  | %04x %04x %04x %04x %04x %04x %04x %04x\n", packet[0],packet[1],packet[2],packet[3],packet[4],packet[5],packet[6],packet[7],     packet[8], packet[9], packet[10], packet[11], packet[12], packet[13], packet[14], packet[15]);
861   
862   switch (packet[0])
863   {
864   case 0x0000:    // Appears to be a NOP.
865      break;
866
867   case 0x0001:    // Camera transformation.
868      setCameraTransformation(packet);
869      break;
870
871   case 0x0010:    // Lighting information.
872      //if (packet[9]) printPacket(packet, 1);
873      setLighting(packet);
874      break;
875
876   case 0x0011:    // Palette / Model flags?
877      //printPacket(packet, 1); printf("\n");
878      set3dFlags(packet);
879      break;
880
881   case 0x0012:    // Projection Matrix
882      //printPacket(packet, 1);
883      setCameraProjectionMatrix(packet);
884      break;
885
886   case 0x0100:
887   case 0x0101:    // Geometry with full transformations
888      // HACK.  Masks out a piece of geo bbust2's drawShaded() crashes on.
889      if (packet[2] == 0x0003 && packet[3] == 0x8f37 && m_mcu_type == SHOOT_MCU)
890         break;
891
892      recoverPolygonBlock( packet, polys, &numPolys);
893      break;
894
895   case 0x0102:    // Geometry with only translation
896      // HACK.  Give up on strange calls to 0102.
897      if (packet[8] != 0x0102)
898      {
899         // It appears as though packet[7] might hold the magic #
900         // Almost looks like there is a chain mode for these guys.  Same for 0101?
901         // printf("WARNING: "); printPacket(packet, 1);
902         break;
903      }
904
905      // Split the packet and call recoverPolygonBlock on each half.
906      UINT16 miniPacket[16];
907      memset(miniPacket, 0, sizeof(UINT16)*16);
908      for (int i = 0; i < 7; i++) miniPacket[i] = packet[i];
909      miniPacket[7] = 0x7fff;
910      miniPacket[11] = 0x7fff;
911      miniPacket[15] = 0x7fff;
912      recoverPolygonBlock( miniPacket, polys, &numPolys);
913
914      memset(miniPacket, 0, sizeof(UINT16)*16);
915      for (int i = 0; i < 7; i++) miniPacket[i] = packet[i+8];
916      for (int i = 0; i < 7; i++) miniPacket[i] = packet[i+8];
917      miniPacket[7] = 0x7fff;
918      miniPacket[11] = 0x7fff;
919      miniPacket[15] = 0x7fff;
920      recoverPolygonBlock( miniPacket, polys, &numPolys);
921      break;
922
923   case 0x1000:    // Unknown: Some sort of global flags?
924      //printPacket(packet, 1); printf("\n");
925      break;
926
927   case 0x1001:    // Unknown: Some sort of global flags (a group of 4, actually)?
928      //printPacket(packet, 1);
929      break;
930
931   default:
932      printf("HNG64: Unknown 3d command %04x.\n", packet[0]);
933      break;
934   }
935
936   /* If there are polygons, rasterize them into the display buffer */
937   for (int i = 0; i < numPolys; i++)
938   {
939      if (polys[i].visible)
940      {
941         drawShaded( &polys[i]);
942      }
943   }
944}
945
946void hng64_state::clear3d()
947{
948   int i;
949
950   const rectangle &visarea = m_screen->visible_area();
951
952   // Reset the buffers...
953   for (i = 0; i < (visarea.max_x)*(visarea.max_y); i++)
954   {
955      m_depthBuffer3d[i] = 100.0f;
956      m_colorBuffer3d[i] = rgb_t(0, 0, 0, 0);
957   }
958
959   // Set some matrices to the identity...
960   setIdentity(m_projectionMatrix);
961   setIdentity(m_modelViewMatrix);
962   setIdentity(m_cameraMatrix);
963}
964
965/* 3D/framebuffer video registers
966 * ------------------------------
967 *
968 * UINT32 | Bits                                    | Use
969 *        | 3322 2222 2222 1111 1111 11             |
970 * -------+-1098-7654-3210-9876-5432-1098-7654-3210-+----------------
971 *      0 | ---- --x- ---- ---- ---- ---- ---- ---- | Reads in Fatal Fury WA, if on then there isn't a 3d refresh (busy flag?).
972 *      0 | ---- ---x ---- ---- ---- ---- ---- ---- | set at POST/service modes, almost likely fb disable
973 *      0 | ???? ???? ???? ???? ccc? ???? ???? ???? | framebuffer color base, 0x311800 in Fatal Fury WA, 0x313800 in Buriki One
974 *      1 |                                         |
975 *      2 | ???? ???? ???? ???? ???? ???? ???? ???? | camera / framebuffer global x/y? Actively used by Samurai Shodown 64 2
976 *      3 | ---- --?x ---- ---- ---- ---- ---- ---- | unknown, unsetted by Buriki One and setted by Fatal Fury WA, buffering mode?
977 *   4-11 | ---- ???? ---- ???? ---- ???? ---- ???? | Table filled with 0x0? data
978 *
979 */
980
981/////////////////////
982// 3D UTILITY CODE //
983/////////////////////
984
985/* 4x4 matrix multiplication */
986void hng64_state::matmul4(float *product, const float *a, const float *b )
987{
988   int i;
989   for (i = 0; i < 4; i++)
990   {
991      const float ai0 = a[0  + i];
992      const float ai1 = a[4  + i];
993      const float ai2 = a[8  + i];
994      const float ai3 = a[12 + i];
995
996      product[0  + i] = ai0 * b[0 ] + ai1 * b[1 ] + ai2 * b[2 ] + ai3 * b[3 ];
997      product[4  + i] = ai0 * b[4 ] + ai1 * b[5 ] + ai2 * b[6 ] + ai3 * b[7 ];
998      product[8  + i] = ai0 * b[8 ] + ai1 * b[9 ] + ai2 * b[10] + ai3 * b[11];
999      product[12 + i] = ai0 * b[12] + ai1 * b[13] + ai2 * b[14] + ai3 * b[15];
1000   }
1001}
1002
1003/* vector by 4x4 matrix multiply */
1004void hng64_state::vecmatmul4(float *product, const float *a, const float *b)
1005{
1006   const float bi0 = b[0];
1007   const float bi1 = b[1];
1008   const float bi2 = b[2];
1009   const float bi3 = b[3];
1010
1011   product[0] = bi0 * a[0] + bi1 * a[4] + bi2 * a[8 ] + bi3 * a[12];
1012   product[1] = bi0 * a[1] + bi1 * a[5] + bi2 * a[9 ] + bi3 * a[13];
1013   product[2] = bi0 * a[2] + bi1 * a[6] + bi2 * a[10] + bi3 * a[14];
1014   product[3] = bi0 * a[3] + bi1 * a[7] + bi2 * a[11] + bi3 * a[15];
1015}
1016
1017float hng64_state::vecDotProduct(const float *a, const float *b)
1018{
1019   return ((a[0]*b[0]) + (a[1]*b[1]) + (a[2]*b[2]));
1020}
1021
1022void hng64_state::setIdentity(float *matrix)
1023{
1024   int i;
1025
1026   for (i = 0; i < 16; i++)
1027   {
1028      matrix[i] = 0.0f;
1029   }
1030
1031   matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1.0f;
1032}
1033
1034float hng64_state::uToF(UINT16 input)
1035{
1036   float retVal;
1037   retVal = (float)((INT16)input) / 32768.0f;
1038   return retVal;
1039
1040#if 0
1041   if ((INT16)input < 0)
1042      retVal = (float)((INT16)input) / 32768.0f;
1043   else
1044      retVal = (float)((INT16)input) / 32767.0f;
1045#endif
1046}
1047
1048void hng64_state::normalize(float* x)
1049{
1050   double l2 = (x[0]*x[0]) + (x[1]*x[1]) + (x[2]*x[2]);
1051   double l = sqrt(l2);
1052
1053   x[0] = (float)(x[0] / l);
1054   x[1] = (float)(x[1] / l);
1055   x[2] = (float)(x[2] / l);
1056}
1057
1058
1059
1060///////////////////////////
1061// POLYGON CLIPPING CODE //
1062///////////////////////////
1063
1064///////////////////////////////////////////////////////////////////////////////////
1065// The remainder of the code in this file is heavily                             //
1066//   influenced by, and sometimes copied verbatim from Andrew Zaferakis' SoftGL  //
1067//   rasterizing system.                                                         //
1068//                                                                               //
1069//   Andrew granted permission for its use in MAME in October of 2004.           //
1070///////////////////////////////////////////////////////////////////////////////////
1071
1072
1073
1074int hng64_state::Inside(struct polyVert *v, int plane)
1075{
1076   switch(plane)
1077   {
1078   case HNG64_LEFT:
1079      return (v->clipCoords[0] >= -v->clipCoords[3]) ? 1 : 0;
1080   case HNG64_RIGHT:
1081      return (v->clipCoords[0] <=  v->clipCoords[3]) ? 1 : 0;
1082
1083   case HNG64_TOP:
1084      return (v->clipCoords[1] <=  v->clipCoords[3]) ? 1 : 0;
1085   case HNG64_BOTTOM:
1086      return (v->clipCoords[1] >= -v->clipCoords[3]) ? 1 : 0;
1087
1088   case HNG64_NEAR:
1089      return (v->clipCoords[2] <=  v->clipCoords[3]) ? 1 : 0;
1090   case HNG64_FAR:
1091      return (v->clipCoords[2] >= -v->clipCoords[3]) ? 1 : 0;
1092   }
1093
1094   return 0;
1095}
1096
1097void hng64_state::Intersect(struct polyVert *input0, struct polyVert *input1, struct polyVert *output, int plane)
1098{
1099   float t = 0.0f;
1100
1101   float *Iv0 = input0->clipCoords;
1102   float *Iv1 = input1->clipCoords;
1103   float *Ov  = output->clipCoords;
1104
1105   float *It0 = input0->texCoords;
1106   float *It1 = input1->texCoords;
1107   float *Ot  = output->texCoords;
1108
1109   float *Il0 = input0->light;
1110   float *Il1 = input1->light;
1111   float *Ol  = output->light;
1112
1113   switch(plane)
1114   {
1115   case HNG64_LEFT:
1116      t = (Iv0[0]+Iv0[3]) / (-Iv1[3]+Iv0[3]-Iv1[0]+Iv0[0]);
1117      break;
1118   case HNG64_RIGHT:
1119      t = (Iv0[0]-Iv0[3]) / (Iv1[3]-Iv0[3]-Iv1[0]+Iv0[0]);
1120      break;
1121   case HNG64_TOP:
1122      t = (Iv0[1]-Iv0[3]) / (Iv1[3]-Iv0[3]-Iv1[1]+Iv0[1]);
1123      break;
1124   case HNG64_BOTTOM:
1125      t = (Iv0[1]+Iv0[3]) / (-Iv1[3]+Iv0[3]-Iv1[1]+Iv0[1]);
1126      break;
1127   case HNG64_NEAR:
1128      t = (Iv0[2]-Iv0[3]) / (Iv1[3]-Iv0[3]-Iv1[2]+Iv0[2]);
1129      break;
1130   case HNG64_FAR:
1131      t = (Iv0[2]+Iv0[3]) / (-Iv1[3]+Iv0[3]-Iv1[2]+Iv0[2]);
1132      break;
1133   }
1134
1135   Ov[0] = Iv0[0] + (Iv1[0] - Iv0[0]) * t;
1136   Ov[1] = Iv0[1] + (Iv1[1] - Iv0[1]) * t;
1137   Ov[2] = Iv0[2] + (Iv1[2] - Iv0[2]) * t;
1138   Ov[3] = Iv0[3] + (Iv1[3] - Iv0[3]) * t;
1139
1140   Ot[0] = It0[0] + (It1[0] - It0[0]) * t;
1141   Ot[1] = It0[1] + (It1[1] - It0[1]) * t;
1142   Ot[2] = It0[2] + (It1[2] - It0[2]) * t;
1143   Ot[3] = It0[3] + (It1[3] - It0[3]) * t;
1144
1145   Ol[0] = Il0[0] + (Il1[0] - Il0[0]) * t;
1146   Ol[1] = Il0[1] + (Il1[1] - Il0[1]) * t;
1147   Ol[2] = Il0[2] + (Il1[2] - Il0[2]) * t;
1148}
1149
1150void hng64_state::performFrustumClip(struct polygon *p)
1151{
1152   int i, j, k;
1153   //////////////////////////////////////////////////////////////////////////
1154   // Clip against the volumes defined by the homogeneous clip coordinates //
1155   //////////////////////////////////////////////////////////////////////////
1156
1157   struct polygon temp;
1158
1159   struct polyVert *v0;
1160   struct polyVert *v1;
1161   struct polyVert *tv;
1162
1163   temp.n = 0;
1164
1165   // Skip near and far clipping planes ?
1166   for (j = 0; j <= HNG64_BOTTOM; j++)
1167   {
1168      for (i = 0; i < p->n; i++)
1169      {
1170         k = (i+1) % p->n; // Index of next vertex
1171
1172         v0 = &p->vert[i];
1173         v1 = &p->vert[k];
1174
1175         tv = &temp.vert[temp.n];
1176
1177         if (Inside(v0, j) && Inside(v1, j))                         // Edge is completely inside the volume...
1178         {
1179            memcpy(tv, v1, sizeof(struct polyVert));
1180            temp.n++;
1181         }
1182
1183         else if (Inside(v0, j) && !Inside(v1, j))                   // Edge goes from in to out...
1184         {
1185            Intersect(v0, v1, tv, j);
1186            temp.n++;
1187         }
1188
1189         else if (!Inside(v0, j) && Inside(v1, j))                   // Edge goes from out to in...
1190         {
1191            Intersect(v0, v1, tv, j);
1192            memcpy(&temp.vert[temp.n+1], v1, sizeof(struct polyVert));
1193            temp.n+=2;
1194         }
1195      }
1196
1197      p->n = temp.n;
1198
1199      for (i = 0; i < temp.n; i++)
1200      {
1201         memcpy(&p->vert[i], &temp.vert[i], sizeof(struct polyVert));
1202      }
1203
1204      temp.n = 0;
1205   }
1206}
1207
1208
1209
1210/*********************************************************************/
1211/**   FillSmoothTexPCHorizontalLine                                 **/
1212/**     Input: Color Buffer (framebuffer), depth buffer, width and  **/
1213/**            height of framebuffer, starting, and ending values   **/
1214/**            for x and y, constant y.  Fills horizontally with    **/
1215/**            z,r,g,b interpolation.                               **/
1216/**                                                                 **/
1217/**     Output: none                                                **/
1218/*********************************************************************/
1219inline void hng64_state::FillSmoothTexPCHorizontalLine(
1220                                 const polygonRasterOptions& prOptions,
1221                                 int x_start, int x_end, int y, float z_start, float z_delta,
1222                                 float w_start, float w_delta, float r_start, float r_delta,
1223                                 float g_start, float g_delta, float b_start, float b_delta,
1224                                 float s_start, float s_delta, float t_start, float t_delta)
1225{
1226   float*  db = &(m_depthBuffer3d[(y * m_screen->visible_area().max_x) + x_start]);
1227   UINT32* cb = &(m_colorBuffer3d[(y * m_screen->visible_area().max_x) + x_start]);
1228
1229   UINT8 paletteEntry = 0;
1230   float t_coord, s_coord;
1231   const UINT8 *gfx = m_texturerom;   
1232   const UINT8 *textureOffset = &gfx[prOptions.texIndex * 1024 * 1024];
1233
1234   for (; x_start <= x_end; x_start++)
1235   {
1236      if (z_start < (*db))
1237      {
1238         // MULTIPLY BACK THROUGH BY W
1239         t_coord = t_start / w_start;
1240         s_coord = s_start / w_start;
1241
1242         if ((prOptions.debugColor & 0xff000000) == 0x01000000)
1243         {
1244            // UV COLOR MODE
1245            *cb = rgb_t(255, (UINT8)(s_coord*255.0f), (UINT8)(t_coord*255.0f), (UINT8)(0));
1246            *db = z_start;
1247         }
1248         else if ((prOptions.debugColor & 0xff000000) == 0x02000000)
1249         {
1250            // Lit
1251            *cb = rgb_t(255, (UINT8)(r_start/w_start), (UINT8)(g_start/w_start), (UINT8)(b_start/w_start));
1252            *db = z_start;
1253         }
1254         else if ((prOptions.debugColor & 0xff000000) == 0xff000000)
1255         {
1256            // DEBUG COLOR MODE
1257            *cb = prOptions.debugColor;
1258            *db = z_start;
1259         }
1260         else
1261         {
1262            float textureS = 0.0f;
1263            float textureT = 0.0f;
1264
1265            // Standard & Half-Res textures
1266            if (prOptions.texType == 0x0)
1267            {
1268               textureS = s_coord * 1024.0f;
1269               textureT = t_coord * 1024.0f;
1270            }
1271            else if (prOptions.texType == 0x1)
1272            {
1273               textureS = s_coord * 512.0f;
1274               textureT = t_coord * 512.0f;
1275            }
1276
1277            // Small-Page textures
1278            if (prOptions.texPageSmall)
1279            {
1280               textureT = fmod(textureT, 256.0f);
1281               textureS = fmod(textureS, 256.0f);
1282
1283               textureT += (256.0f * prOptions.texPageHorizOffset);
1284               textureS += (256.0f * prOptions.texPageVertOffset);
1285            }
1286            paletteEntry = textureOffset[((int)textureS)*1024 + (int)textureT];
1287
1288            // Naieve Alpha Implementation (?) - don't draw if you're at texture index 0...
1289            if (paletteEntry != 0)
1290            {
1291               // The color out of the texture
1292               paletteEntry %= prOptions.palPageSize;
1293               rgb_t color = m_palette->pen(prOptions.palOffset + paletteEntry);
1294
1295               // Apply the lighting
1296               float rIntensity = (r_start/w_start) / 255.0f;
1297               float gIntensity = (g_start/w_start) / 255.0f;
1298               float bIntensity = (b_start/w_start) / 255.0f;
1299               float red   = color.r()   * rIntensity;
1300               float green = color.g() * gIntensity;
1301               float blue  = color.b()  * bIntensity;
1302
1303               // Clamp and finalize
1304               red = color.r() + red;
1305               green = color.g() + green;
1306               blue = color.b() + blue;
1307
1308               if (red >= 255) red = 255;
1309               if (green >= 255) green = 255;
1310               if (blue >= 255) blue = 255;
1311
1312               color = rgb_t(255, (UINT8)red, (UINT8)green, (UINT8)blue);
1313
1314               *cb = color;
1315               *db = z_start;
1316            }
1317         }
1318      }
1319      db++;
1320      cb++;
1321      z_start += z_delta;
1322      w_start += w_delta;
1323      r_start += r_delta;
1324      g_start += g_delta;
1325      b_start += b_delta;
1326      s_start += s_delta;
1327      t_start += t_delta;
1328   }
1329}
1330
1331//----------------------------------------------------------------------------
1332// Given 3D triangle ABC in screen space with clipped coordinates within the following
1333// bounds: x in [0,W], y in [0,H], z in [0,1]. The origin for (x,y) is in the bottom
1334// left corner of the pixel grid. z=0 is the near plane and z=1 is the far plane,
1335// so lesser values are closer. The coordinates of the pixels are evenly spaced
1336// in x and y 1 units apart starting at the bottom-left pixel with coords
1337// (0.5,0.5). In other words, the pixel sample point is in the center of the
1338// rectangular grid cell containing the pixel sample. The framebuffer has
1339// dimensions width x height (WxH). The Color buffer is a 1D array (row-major
1340// order) with 3 unsigned chars per pixel (24-bit color). The Depth buffer is
1341// a 1D array (also row-major order) with a float value per pixel
1342// For a pixel location (x,y) we can obtain
1343// the Color and Depth array locations as: Color[(((int)y)*W+((int)x))*3]
1344// (for the red value, green is offset +1, and blue is offset +2 and
1345// Depth[((int)y)*W+((int)x)]. Fills the pixels contained in the triangle
1346// with the global current color and the properly linearly interpolated depth
1347// value (performs Z-buffer depth test before writing new pixel).
1348// Pixel samples that lie inside the triangle edges are filled with
1349// a bias towards the minimum values (samples that lie exactly on a triangle
1350// edge are filled only for minimum x values along a horizontal span and for
1351// minimum y values, samples lying on max values are not filled).
1352// Per-vertex colors are RGB floating point triplets in [0.0,255.0]. The vertices
1353// include their w-components for use in linearly interpolating perspectively
1354// correct color (RGB) and texture-coords (st) across the face of the triangle.
1355// A texture image of RGB floating point triplets of size TWxWH is also given.
1356// Texture colors are normalized RGB values in [0,1].
1357//   clamp and repeat wrapping modes : Wrapping={0,1}
1358//   nearest and bilinear filtering: Filtering={0,1}
1359//   replace and modulate application modes: Function={0,1}
1360//---------------------------------------------------------------------------
1361void hng64_state::RasterizeTriangle_SMOOTH_TEX_PC(
1362                                 float A[4], float B[4], float C[4],
1363                                 float Ca[3], float Cb[3], float Cc[3], // PER-VERTEX RGB COLORS
1364                                 float Ta[2], float Tb[2], float Tc[2], // PER-VERTEX (S,T) TEX-COORDS
1365                                 const polygonRasterOptions& prOptions)
1366{
1367   // Get our order of points by increasing y-coord
1368   float *p_min = ((A[1] <= B[1]) && (A[1] <= C[1])) ? A : ((B[1] <= A[1]) && (B[1] <= C[1])) ? B : C;
1369   float *p_max = ((A[1] >= B[1]) && (A[1] >= C[1])) ? A : ((B[1] >= A[1]) && (B[1] >= C[1])) ? B : C;
1370   float *p_mid = ((A != p_min) && (A != p_max)) ? A : ((B != p_min) && (B != p_max)) ? B : C;
1371
1372   // Perspectively correct color interpolation, interpolate r/w, g/w, b/w, then divide by 1/w at each pixel (A[3] = 1/w)
1373   float ca[3], cb[3], cc[3];
1374   float ta[2], tb[2], tc[2];
1375
1376   float *c_min;
1377   float *c_mid;
1378   float *c_max;
1379
1380   // We must keep the tex coords straight with the point ordering
1381   float *t_min;
1382   float *t_mid;
1383   float *t_max;
1384
1385   // Find out control points for y, this divides the triangle into upper and lower
1386   int   y_min;
1387   int   y_max;
1388   int   y_mid;
1389
1390   // Compute the slopes of each line, and color this is used to determine the interpolation
1391   float x1_slope;
1392   float x2_slope;
1393   float z1_slope;
1394   float z2_slope;
1395   float w1_slope;
1396   float w2_slope;
1397   float r1_slope;
1398   float r2_slope;
1399   float g1_slope;
1400   float g2_slope;
1401   float b1_slope;
1402   float b2_slope;
1403   float s1_slope;
1404   float s2_slope;
1405   float t1_slope;
1406   float t2_slope;
1407
1408   // Compute the t values used in the equation Ax = Ax + (Bx - Ax)*t
1409   // We only need one t, because it is only used to compute the start.
1410   // Create storage for the interpolated x and z values for both lines
1411   // also for the RGB interpolation
1412   float t;
1413   float x1_interp;
1414   float z1_interp;
1415   float w1_interp;
1416   float r1_interp;
1417   float g1_interp;
1418   float b1_interp;
1419   float s1_interp;
1420   float t1_interp;
1421
1422   float x2_interp;
1423   float z2_interp;
1424   float w2_interp;
1425   float r2_interp;
1426   float g2_interp;
1427   float b2_interp;
1428   float s2_interp;
1429   float t2_interp;
1430
1431   // Create storage for the horizontal interpolation of z and RGB color and its starting points
1432   // This is used to fill the triangle horizontally
1433   int   x_start,     x_end;
1434   float z_interp_x,  z_delta_x;
1435   float w_interp_x,  w_delta_x;
1436   float r_interp_x,  r_delta_x;
1437   float g_interp_x,  g_delta_x;
1438   float b_interp_x,  b_delta_x;
1439   float s_interp_x,  s_delta_x;
1440   float t_interp_x,  t_delta_x;
1441
1442   ca[0] = Ca[0]; ca[1] = Ca[1]; ca[2] = Ca[2];
1443   cb[0] = Cb[0]; cb[1] = Cb[1]; cb[2] = Cb[2];
1444   cc[0] = Cc[0]; cc[1] = Cc[1]; cc[2] = Cc[2];
1445
1446   // Perspectively correct tex interpolation, interpolate s/w, t/w, then divide by 1/w at each pixel (A[3] = 1/w)
1447   ta[0] = Ta[0]; ta[1] = Ta[1];
1448   tb[0] = Tb[0]; tb[1] = Tb[1];
1449   tc[0] = Tc[0]; tc[1] = Tc[1];
1450
1451   // We must keep the colors straight with the point ordering
1452   c_min = (p_min == A) ? ca : (p_min == B) ? cb : cc;
1453   c_mid = (p_mid == A) ? ca : (p_mid == B) ? cb : cc;
1454   c_max = (p_max == A) ? ca : (p_max == B) ? cb : cc;
1455
1456   // We must keep the tex coords straight with the point ordering
1457   t_min = (p_min == A) ? ta : (p_min == B) ? tb : tc;
1458   t_mid = (p_mid == A) ? ta : (p_mid == B) ? tb : tc;
1459   t_max = (p_max == A) ? ta : (p_max == B) ? tb : tc;
1460
1461   // Find out control points for y, this divides the triangle into upper and lower
1462   y_min  = (((int)p_min[1]) + 0.5 >= p_min[1]) ? (int)p_min[1] : ((int)p_min[1]) + 1;
1463   y_max  = (((int)p_max[1]) + 0.5 <  p_max[1]) ? (int)p_max[1] : ((int)p_max[1]) - 1;
1464   y_mid  = (((int)p_mid[1]) + 0.5 >= p_mid[1]) ? (int)p_mid[1] : ((int)p_mid[1]) + 1;
1465
1466   // Compute the slopes of each line, and color this is used to determine the interpolation
1467   x1_slope = (p_max[0] - p_min[0]) / (p_max[1] - p_min[1]);
1468   x2_slope = (p_mid[0] - p_min[0]) / (p_mid[1] - p_min[1]);
1469   z1_slope = (p_max[2] - p_min[2]) / (p_max[1] - p_min[1]);
1470   z2_slope = (p_mid[2] - p_min[2]) / (p_mid[1] - p_min[1]);
1471   w1_slope = (p_max[3] - p_min[3]) / (p_max[1] - p_min[1]);
1472   w2_slope = (p_mid[3] - p_min[3]) / (p_mid[1] - p_min[1]);
1473   r1_slope = (c_max[0] - c_min[0]) / (p_max[1] - p_min[1]);
1474   r2_slope = (c_mid[0] - c_min[0]) / (p_mid[1] - p_min[1]);
1475   g1_slope = (c_max[1] - c_min[1]) / (p_max[1] - p_min[1]);
1476   g2_slope = (c_mid[1] - c_min[1]) / (p_mid[1] - p_min[1]);
1477   b1_slope = (c_max[2] - c_min[2]) / (p_max[1] - p_min[1]);
1478   b2_slope = (c_mid[2] - c_min[2]) / (p_mid[1] - p_min[1]);
1479   s1_slope = (t_max[0] - t_min[0]) / (p_max[1] - p_min[1]);
1480   s2_slope = (t_mid[0] - t_min[0]) / (p_mid[1] - p_min[1]);
1481   t1_slope = (t_max[1] - t_min[1]) / (p_max[1] - p_min[1]);
1482   t2_slope = (t_mid[1] - t_min[1]) / (p_mid[1] - p_min[1]);
1483
1484   // Compute the t values used in the equation Ax = Ax + (Bx - Ax)*t
1485   // We only need one t, because it is only used to compute the start.
1486   // Create storage for the interpolated x and z values for both lines
1487   // also for the RGB interpolation
1488   t = (((float)y_min) + 0.5 - p_min[1]) / (p_max[1] - p_min[1]);
1489   x1_interp = p_min[0] + (p_max[0] - p_min[0]) * t;
1490   z1_interp = p_min[2] + (p_max[2] - p_min[2]) * t;
1491   w1_interp = p_min[3] + (p_max[3] - p_min[3]) * t;
1492   r1_interp = c_min[0] + (c_max[0] - c_min[0]) * t;
1493   g1_interp = c_min[1] + (c_max[1] - c_min[1]) * t;
1494   b1_interp = c_min[2] + (c_max[2] - c_min[2]) * t;
1495   s1_interp = t_min[0] + (t_max[0] - t_min[0]) * t;
1496   t1_interp = t_min[1] + (t_max[1] - t_min[1]) * t;
1497
1498   t = (((float)y_min) + 0.5 - p_min[1]) / (p_mid[1] - p_min[1]);
1499   x2_interp = p_min[0] + (p_mid[0] - p_min[0]) * t;
1500   z2_interp = p_min[2] + (p_mid[2] - p_min[2]) * t;
1501   w2_interp = p_min[3] + (p_mid[3] - p_min[3]) * t;
1502   r2_interp = c_min[0] + (c_mid[0] - c_min[0]) * t;
1503   g2_interp = c_min[1] + (c_mid[1] - c_min[1]) * t;
1504   b2_interp = c_min[2] + (c_mid[2] - c_min[2]) * t;
1505   s2_interp = t_min[0] + (t_mid[0] - t_min[0]) * t;
1506   t2_interp = t_min[1] + (t_mid[1] - t_min[1]) * t;
1507
1508   // First work on the bottom half of the triangle
1509   // I'm using y_min as the incrementer because it saves space and we don't need it anymore
1510   for (; y_min < y_mid; y_min++) {
1511      // We always want to fill left to right, so we have 2 main cases
1512      // Compute the integer starting and ending points and the appropriate z by
1513      // interpolating.  Remember the pixels are in the middle of the grid, i.e. (0.5,0.5,0.5)
1514      if (x1_interp < x2_interp) {
1515         x_start    = ((((int)x1_interp) + 0.5) >= x1_interp) ? (int)x1_interp : ((int)x1_interp) + 1;
1516         x_end      = ((((int)x2_interp) + 0.5) <  x2_interp) ? (int)x2_interp : ((int)x2_interp) - 1;
1517         z_delta_x  = (z2_interp - z1_interp) / (x2_interp - x1_interp);
1518         w_delta_x  = (w2_interp - w1_interp) / (x2_interp - x1_interp);
1519         r_delta_x  = (r2_interp - r1_interp) / (x2_interp - x1_interp);
1520         g_delta_x  = (g2_interp - g1_interp) / (x2_interp - x1_interp);
1521         b_delta_x  = (b2_interp - b1_interp) / (x2_interp - x1_interp);
1522         s_delta_x  = (s2_interp - s1_interp) / (x2_interp - x1_interp);
1523         t_delta_x  = (t2_interp - t1_interp) / (x2_interp - x1_interp);
1524         t          = (x_start + 0.5 - x1_interp) / (x2_interp - x1_interp);
1525         z_interp_x = z1_interp + (z2_interp - z1_interp) * t;
1526         w_interp_x = w1_interp + (w2_interp - w1_interp) * t;
1527         r_interp_x = r1_interp + (r2_interp - r1_interp) * t;
1528         g_interp_x = g1_interp + (g2_interp - g1_interp) * t;
1529         b_interp_x = b1_interp + (b2_interp - b1_interp) * t;
1530         s_interp_x = s1_interp + (s2_interp - s1_interp) * t;
1531         t_interp_x = t1_interp + (t2_interp - t1_interp) * t;
1532
1533      } else {
1534         x_start    = ((((int)x2_interp) + 0.5) >= x2_interp) ? (int)x2_interp : ((int)x2_interp) + 1;
1535         x_end      = ((((int)x1_interp) + 0.5) <  x1_interp) ? (int)x1_interp : ((int)x1_interp) - 1;
1536         z_delta_x  = (z1_interp - z2_interp) / (x1_interp - x2_interp);
1537         w_delta_x  = (w1_interp - w2_interp) / (x1_interp - x2_interp);
1538         r_delta_x  = (r1_interp - r2_interp) / (x1_interp - x2_interp);
1539         g_delta_x  = (g1_interp - g2_interp) / (x1_interp - x2_interp);
1540         b_delta_x  = (b1_interp - b2_interp) / (x1_interp - x2_interp);
1541         s_delta_x  = (s1_interp - s2_interp) / (x1_interp - x2_interp);
1542         t_delta_x  = (t1_interp - t2_interp) / (x1_interp - x2_interp);
1543         t          = (x_start + 0.5 - x2_interp) / (x1_interp - x2_interp);
1544         z_interp_x = z2_interp + (z1_interp - z2_interp) * t;
1545         w_interp_x = w2_interp + (w1_interp - w2_interp) * t;
1546         r_interp_x = r2_interp + (r1_interp - r2_interp) * t;
1547         g_interp_x = g2_interp + (g1_interp - g2_interp) * t;
1548         b_interp_x = b2_interp + (b1_interp - b2_interp) * t;
1549         s_interp_x = s2_interp + (s1_interp - s2_interp) * t;
1550         t_interp_x = t2_interp + (t1_interp - t2_interp) * t;
1551      }
1552
1553      // Pass the horizontal line to the filler, this could be put in the routine
1554      // then interpolate for the next values of x and z
1555      FillSmoothTexPCHorizontalLine( prOptions,
1556         x_start, x_end, y_min, z_interp_x, z_delta_x, w_interp_x, w_delta_x,
1557         r_interp_x, r_delta_x, g_interp_x, g_delta_x, b_interp_x, b_delta_x,
1558         s_interp_x, s_delta_x, t_interp_x, t_delta_x);
1559      x1_interp += x1_slope;   z1_interp += z1_slope;
1560      x2_interp += x2_slope;   z2_interp += z2_slope;
1561      r1_interp += r1_slope;   r2_interp += r2_slope;
1562      g1_interp += g1_slope;   g2_interp += g2_slope;
1563      b1_interp += b1_slope;   b2_interp += b2_slope;
1564      w1_interp += w1_slope;   w2_interp += w2_slope;
1565      s1_interp += s1_slope;   s2_interp += s2_slope;
1566      t1_interp += t1_slope;   t2_interp += t2_slope;
1567   }
1568
1569   // Now do the same thing for the top half of the triangle.
1570   // We only need to recompute the x2 line because it changes at the midpoint
1571   x2_slope = (p_max[0] - p_mid[0]) / (p_max[1] - p_mid[1]);
1572   z2_slope = (p_max[2] - p_mid[2]) / (p_max[1] - p_mid[1]);
1573   w2_slope = (p_max[3] - p_mid[3]) / (p_max[1] - p_mid[1]);
1574   r2_slope = (c_max[0] - c_mid[0]) / (p_max[1] - p_mid[1]);
1575   g2_slope = (c_max[1] - c_mid[1]) / (p_max[1] - p_mid[1]);
1576   b2_slope = (c_max[2] - c_mid[2]) / (p_max[1] - p_mid[1]);
1577   s2_slope = (t_max[0] - t_mid[0]) / (p_max[1] - p_mid[1]);
1578   t2_slope = (t_max[1] - t_mid[1]) / (p_max[1] - p_mid[1]);
1579
1580   t = (((float)y_mid) + 0.5 - p_mid[1]) / (p_max[1] - p_mid[1]);
1581   x2_interp = p_mid[0] + (p_max[0] - p_mid[0]) * t;
1582   z2_interp = p_mid[2] + (p_max[2] - p_mid[2]) * t;
1583   w2_interp = p_mid[3] + (p_max[3] - p_mid[3]) * t;
1584   r2_interp = c_mid[0] + (c_max[0] - c_mid[0]) * t;
1585   g2_interp = c_mid[1] + (c_max[1] - c_mid[1]) * t;
1586   b2_interp = c_mid[2] + (c_max[2] - c_mid[2]) * t;
1587   s2_interp = t_mid[0] + (t_max[0] - t_mid[0]) * t;
1588   t2_interp = t_mid[1] + (t_max[1] - t_mid[1]) * t;
1589
1590   // We've seen this loop before haven't we?
1591   // I'm using y_mid as the incrementer because it saves space and we don't need it anymore
1592   for (; y_mid <= y_max; y_mid++) {
1593      if (x1_interp < x2_interp) {
1594         x_start    = ((((int)x1_interp) + 0.5) >= x1_interp) ? (int)x1_interp : ((int)x1_interp) + 1;
1595         x_end      = ((((int)x2_interp) + 0.5) <  x2_interp) ? (int)x2_interp : ((int)x2_interp) - 1;
1596         z_delta_x  = (z2_interp - z1_interp) / (x2_interp - x1_interp);
1597         w_delta_x  = (w2_interp - w1_interp) / (x2_interp - x1_interp);
1598         r_delta_x  = (r2_interp - r1_interp) / (x2_interp - x1_interp);
1599         g_delta_x  = (g2_interp - g1_interp) / (x2_interp - x1_interp);
1600         b_delta_x  = (b2_interp - b1_interp) / (x2_interp - x1_interp);
1601         s_delta_x  = (s2_interp - s1_interp) / (x2_interp - x1_interp);
1602         t_delta_x  = (t2_interp - t1_interp) / (x2_interp - x1_interp);
1603         t          = (x_start + 0.5 - x1_interp) / (x2_interp - x1_interp);
1604         z_interp_x = z1_interp + (z2_interp - z1_interp) * t;
1605         w_interp_x = w1_interp + (w2_interp - w1_interp) * t;
1606         r_interp_x = r1_interp + (r2_interp - r1_interp) * t;
1607         g_interp_x = g1_interp + (g2_interp - g1_interp) * t;
1608         b_interp_x = b1_interp + (b2_interp - b1_interp) * t;
1609         s_interp_x = s1_interp + (s2_interp - s1_interp) * t;
1610         t_interp_x = t1_interp + (t2_interp - t1_interp) * t;
1611
1612      } else {
1613         x_start    = ((((int)x2_interp) + 0.5) >= x2_interp) ? (int)x2_interp : ((int)x2_interp) + 1;
1614         x_end      = ((((int)x1_interp) + 0.5) <  x1_interp) ? (int)x1_interp : ((int)x1_interp) - 1;
1615         z_delta_x  = (z1_interp - z2_interp) / (x1_interp - x2_interp);
1616         w_delta_x  = (w1_interp - w2_interp) / (x1_interp - x2_interp);
1617         r_delta_x  = (r1_interp - r2_interp) / (x1_interp - x2_interp);
1618         g_delta_x  = (g1_interp - g2_interp) / (x1_interp - x2_interp);
1619         b_delta_x  = (b1_interp - b2_interp) / (x1_interp - x2_interp);
1620         s_delta_x  = (s1_interp - s2_interp) / (x1_interp - x2_interp);
1621         t_delta_x  = (t1_interp - t2_interp) / (x1_interp - x2_interp);
1622         t          = (x_start + 0.5 - x2_interp) / (x1_interp - x2_interp);
1623         z_interp_x = z2_interp + (z1_interp - z2_interp) * t;
1624         w_interp_x = w2_interp + (w1_interp - w2_interp) * t;
1625         r_interp_x = r2_interp + (r1_interp - r2_interp) * t;
1626         g_interp_x = g2_interp + (g1_interp - g2_interp) * t;
1627         b_interp_x = b2_interp + (b1_interp - b2_interp) * t;
1628         s_interp_x = s2_interp + (s1_interp - s2_interp) * t;
1629         t_interp_x = t2_interp + (t1_interp - t2_interp) * t;
1630      }
1631
1632      // Pass the horizontal line to the filler, this could be put in the routine
1633      // then interpolate for the next values of x and z
1634      FillSmoothTexPCHorizontalLine( prOptions,
1635         x_start, x_end, y_mid, z_interp_x, z_delta_x, w_interp_x, w_delta_x,
1636         r_interp_x, r_delta_x, g_interp_x, g_delta_x, b_interp_x, b_delta_x,
1637         s_interp_x, s_delta_x, t_interp_x, t_delta_x);
1638      x1_interp += x1_slope;   z1_interp += z1_slope;
1639      x2_interp += x2_slope;   z2_interp += z2_slope;
1640      r1_interp += r1_slope;   r2_interp += r2_slope;
1641      g1_interp += g1_slope;   g2_interp += g2_slope;
1642      b1_interp += b1_slope;   b2_interp += b2_slope;
1643      w1_interp += w1_slope;   w2_interp += w2_slope;
1644      s1_interp += s1_slope;   s2_interp += s2_slope;
1645      t1_interp += t1_slope;   t2_interp += t2_slope;
1646   }
1647}
1648
1649void hng64_state::drawShaded( struct polygon *p)
1650{
1651   // The perspective-correct texture divide...
1652   // !!! There is a very good chance the HNG64 hardware does not do perspective-correct texture-mapping !!!
1653   int j;
1654   for (j = 0; j < p->n; j++)
1655   {
1656      p->vert[j].clipCoords[3] = 1.0f / p->vert[j].clipCoords[3];
1657      p->vert[j].light[0]      = p->vert[j].light[0]     * p->vert[j].clipCoords[3];
1658      p->vert[j].light[1]      = p->vert[j].light[1]     * p->vert[j].clipCoords[3];
1659      p->vert[j].light[2]      = p->vert[j].light[2]     * p->vert[j].clipCoords[3];
1660      p->vert[j].texCoords[0]  = p->vert[j].texCoords[0] * p->vert[j].clipCoords[3];
1661      p->vert[j].texCoords[1]  = p->vert[j].texCoords[1] * p->vert[j].clipCoords[3];
1662   }
1663
1664   // Set up the struct that will pass the polygon's options around.
1665   polygonRasterOptions prOptions;
1666   prOptions.texType = p->texType;
1667   prOptions.texIndex = p->texIndex;
1668   prOptions.palOffset = p->palOffset;
1669   prOptions.palPageSize = p->palPageSize;
1670   prOptions.debugColor = p->debugColor;
1671   prOptions.texPageSmall = p->texPageSmall;
1672   prOptions.texPageHorizOffset = p->texPageHorizOffset;
1673   prOptions.texPageVertOffset = p->texPageVertOffset;
1674
1675   for (j = 1; j < p->n-1; j++)
1676   {
1677      RasterizeTriangle_SMOOTH_TEX_PC(
1678                              p->vert[0].clipCoords, p->vert[j].clipCoords, p->vert[j+1].clipCoords,
1679                              p->vert[0].light,      p->vert[j].light,      p->vert[j+1].light,
1680                              p->vert[0].texCoords,  p->vert[j].texCoords,  p->vert[j+1].texCoords,
1681                              prOptions);
1682   }
1683}
1684
trunk/src/mame/video/hng64_sprite.c
r0r244701
1
2/* Hyper NeoGeo 64 Sprite bits */
3
4#include "includes/hng64.h"
5
6/*
7 * Sprite Format
8 * ------------------
9 *
10 * UINT32 | Bits                                    | Use
11 *        | 3322 2222 2222 1111 1111 11             |
12 * -------+-1098-7654-3210-9876-5432-1098-7654-3210-+----------------
13 *   0    | yyyy yyyy yyyy yyyy xxxx xxxx xxxx xxxx | x/y position
14 *   1    | YYYY YYYY YYYY YYYY XXXX XXXX XXXX XXXX | x/y zoom (*)
15 *   2    | ---- -zzz zzzz zzzz ---- ---I cccc CCCC | Z-buffer value, 'Inline' chain flag, x/y chain
16 *   3    | ---- ---- pppp pppp ---- ---- ---- ---- | palette entry
17 *   4    | mmmm -?fF a??? tttt tttt tttt tttt tttt | mosaic factor, unknown (**) , flip bits, additive blending, unknown (***), tile number
18 *   5    | ---- ---- ---- ---- ---- ---- ---- ---- | not used ??
19 *   6    | ---- ---- ---- ---- ---- ---- ---- ---- | not used ??
20 *   7    | ---- ---- ---- ---- ---- ---- ---- ---- | not used ??
21 *
22 * (*) Fatal Fury WA standard elements are 0x1000-0x1000, all the other games sets 0x100-0x100, related to the bit 27 of sprite regs 0?
23 * (**) setted by black squares in ranking screen in Samurai Shodown 64 1, sprite disable?
24 * (***) bit 22 is setted on some Fatal Fury WA snow (not all of them), bit 21 is setted on Xrally how to play elements in attract mode
25 *
26 * Sprite Global Registers
27 * -----------------------
28 *
29 * UINT32 | Bits                                    | Use
30 *        | 3322 2222 2222 1111 1111 11             |
31 * -------+-1098-7654-3210-9876-5432-1098-7654-3210-+----------------
32 *   0    | ---- z--- b--- ---- ---- ---- ---- ---- | zooming mode, bpp select
33 *   1    | yyyy yyyy yyyy yyyy xxxx xxxx xxxx xxxx | global sprite offset (ss64 rankings in attract)
34 *   2    | ---- ---- ---- ---- ---- ---- ---- ---- |
35 *   3    | ---- ---- ---- ---- ---- ---- ---- ---- |
36 *   4    | ---- ---- ---- ---- ---- ---- ---- ---- |
37 * (anything else is unknown at the current time)
38 * Notes:
39 * [0]
40 * 0xf0000000 setted in both Samurai Shodown
41 * 0x00060000 always setted in all the games
42 * 0x00010000 setted in POST, sprite disable?
43 * [4]
44 * 0x0e0 in Samurai Shodown/Xrally games, 0x1c0 in all the others, zooming factor?
45 */
46
47void hng64_state::draw_sprites(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
48{
49   gfx_element *gfx;
50   UINT32 *source = m_spriteram;
51   UINT32 *finish = m_spriteram + 0xc000/4;
52
53   // global offsets in sprite regs
54   int spriteoffsx = (m_spriteregs[1]>>0)&0xffff;
55   int spriteoffsy = (m_spriteregs[1]>>16)&0xffff;
56
57#if 0
58   for (int iii = 0; iii < 0x0f; iii++)
59      osd_printf_debug("%.8x ", m_videoregs[iii]);
60   osd_printf_debug("\n");
61#endif
62
63   while( source<finish )
64   {
65      int tileno,chainx,chainy,xflip;
66      int pal,xinc,yinc,yflip;
67      UINT16 xpos, ypos;
68      int xdrw,ydrw;
69      int chaini;
70      int zbuf;
71      UINT32 zoomx,zoomy;
72      float foomX, foomY;
73      int blend;
74      int disable;
75
76
77
78      ypos = (source[0]&0xffff0000)>>16;
79      xpos = (source[0]&0x0000ffff)>>0;
80      xpos += (spriteoffsx);
81      ypos += (spriteoffsy);
82
83      tileno= (source[4]&0x0007ffff);
84      blend=  (source[4]&0x00800000);
85      yflip=  (source[4]&0x01000000)>>24;
86      xflip=  (source[4]&0x02000000)>>25;
87      disable=(source[4]&0x04000000)>>26; // ss64 rankings?
88
89      pal =(source[3]&0x00ff0000)>>16;
90
91      chainy=(source[2]&0x0000000f);
92      chainx=(source[2]&0x000000f0)>>4;
93      chaini=(source[2]&0x00000100);
94      zbuf = (source[2]&0x07ff0000)>>16; //?
95
96      zoomy = (source[1]&0xffff0000)>>16;
97      zoomx = (source[1]&0x0000ffff)>>0;
98
99      #if 1
100      if(zbuf == 0x7ff) //temp kludge to avoid garbage on screen
101      {
102         source+=8;
103         continue;
104      }
105      #endif
106      if(disable)
107      {
108         source+=8;
109         continue;
110      }
111
112#if 0
113      if (!(source[4] == 0x00000000 || source[4] == 0x000000aa))
114         osd_printf_debug("unknown : %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x \n", source[0], source[1], source[2], source[3],
115            source[4], source[5], source[6], source[7]);
116#endif
117
118      /* Calculate the zoom */
119      {
120         int zoom_factor;
121
122         /* FIXME: regular zoom mode has precision bugs, can be easily seen in Samurai Shodown 64 intro */
123         zoom_factor = (m_spriteregs[0] & 0x08000000) ? 0x1000 : 0x100;
124         if(!zoomx) zoomx=zoom_factor;
125         if(!zoomy) zoomy=zoom_factor;
126
127         /* First, prevent any possible divide by zero errors */
128         foomX = (float)(zoom_factor) / (float)zoomx;
129         foomY = (float)(zoom_factor) / (float)zoomy;
130
131         zoomx = ((int)foomX) << 16;
132         zoomy = ((int)foomY) << 16;
133
134         zoomx += (int)((foomX - floor(foomX)) * (float)0x10000);
135         zoomy += (int)((foomY - floor(foomY)) * (float)0x10000);
136      }
137
138      if (m_spriteregs[0] & 0x00800000) //bpp switch
139      {
140         gfx= m_gfxdecode->gfx(4);
141      }
142      else
143      {
144         gfx= m_gfxdecode->gfx(5);
145         tileno>>=1;
146         pal&=0xf;
147      }
148
149      // Accommodate for chaining and flipping
150      if(xflip)
151      {
152         xinc=-(int)(16.0f*foomX);
153         xpos-=xinc*chainx;
154      }
155      else
156      {
157         xinc=(int)(16.0f*foomX);
158      }
159
160      if(yflip)
161      {
162         yinc=-(int)(16.0f*foomY);
163         ypos-=yinc*chainy;
164      }
165      else
166      {
167         yinc=(int)(16.0f*foomY);
168      }
169
170#if 0
171      if (((source[2) & 0xffff0000) >> 16) == 0x0001)
172      {
173         popmessage("T %.8x %.8x %.8x %.8x %.8x", source[0], source[1], source[2], source[3], source[4]);
174         //popmessage("T %.8x %.8x %.8x %.8x %.8x", source[0], source[1], source[2], source[3], source[4]);
175      }
176#endif
177
178      for(ydrw=0;ydrw<=chainy;ydrw++)
179      {
180         for(xdrw=0;xdrw<=chainx;xdrw++)
181         {
182            INT16 drawx = xpos+(xinc*xdrw);
183            INT16 drawy = ypos+(yinc*ydrw);
184
185            // 0x3ff (0x200 sign bit) based on sams64_2 char select
186            drawx &= 0x3ff;
187            drawy &= 0x3ff;
188
189            if (drawx&0x0200)drawx-=0x400;
190            if (drawy&0x0200)drawy-=0x400;
191
192            if (!chaini)
193            {
194               if (!blend) gfx->prio_zoom_transpen(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0);
195               else gfx->prio_zoom_transpen_additive(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0);
196               tileno++;
197            }
198            else // inline chain mode, used by ss64
199            {
200               tileno=(source[4]&0x0007ffff);
201               pal =(source[3]&0x00ff0000)>>16;
202
203               if (m_spriteregs[0] & 0x00800000) //bpp switch
204               {
205                  gfx= m_gfxdecode->gfx(4);
206               }
207               else
208               {
209                  gfx= m_gfxdecode->gfx(5);
210                  tileno>>=1;
211                  pal&=0xf;
212               }
213
214               if (!blend) gfx->prio_zoom_transpen(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0);
215               else gfx->prio_zoom_transpen_additive(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0);
216               source +=8;
217            }
218
219         }
220      }
221
222      if (!chaini) source +=8;
223   }
224}
225


Previous 199869 Revisions Next


© 1997-2024 The MAME Team