1 /******************************************************************************/
2 /* Mednafen Sega Saturn Emulation Module                                      */
3 /******************************************************************************/
4 /* vdp1_line.cpp - VDP1 Line Drawing Commands Emulation
5 **  Copyright (C) 2015-2020 Mednafen Team
6 **
7 ** This program is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU General Public License
9 ** as published by the Free Software Foundation; either version 2
10 ** of the License, or (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software Foundation, Inc.,
19 ** 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21 
22 #include "ss.h"
23 #include "vdp1_common.h"
24 
25 namespace MDFN_IEN_SS
26 {
27 
28 namespace VDP1
29 {
30 
31 static int32 (*LineFuncTab[2][3][0x20][8 + 1])(bool* need_line_resume) =
32 {
33  #define LINEFN_BC(die, bpp8, b, c)	\
34 	DrawLine<false, false, die, bpp8, c == 0x8, (bool)(b & 0x10), (b & 0x10) && (b & 0x08), (bool)(b & 0x04), false/*b & 0x02*/, (bool)(b & 0x01), (bool)(c & 0x4), (bool)(c & 0x2), (bool)(c & 0x1)>
35 
36  #define LINEFN_B(die, bpp8, b)									\
37 	{										\
38 	 LINEFN_BC(die, bpp8, b, 0x0), LINEFN_BC(die, bpp8, b, 0x1), LINEFN_BC(die, bpp8, b, 0x2), LINEFN_BC(die, bpp8, b, 0x3),	\
39 	 LINEFN_BC(die, bpp8, b, 0x4), LINEFN_BC(die, bpp8, b, 0x5), LINEFN_BC(die, bpp8, b, 0x6), LINEFN_BC(die, bpp8, b, 0x7), 	\
40 	 LINEFN_BC(die, bpp8, b, 0x8), 	/* msb on */						\
41 	}
42 
43  #define LINEFN_BPP8(die, bpp8)									\
44  {												\
45   LINEFN_B(die, bpp8, 0x00), LINEFN_B(die, bpp8, 0x01), LINEFN_B(die, bpp8, 0x02), LINEFN_B(die, bpp8, 0x03),	\
46   LINEFN_B(die, bpp8, 0x04), LINEFN_B(die, bpp8, 0x05), LINEFN_B(die, bpp8, 0x06), LINEFN_B(die, bpp8, 0x07),	\
47   LINEFN_B(die, bpp8, 0x08), LINEFN_B(die, bpp8, 0x09), LINEFN_B(die, bpp8, 0x0A), LINEFN_B(die, bpp8, 0x0B),	\
48   LINEFN_B(die, bpp8, 0x0C), LINEFN_B(die, bpp8, 0x0D), LINEFN_B(die, bpp8, 0x0E), LINEFN_B(die, bpp8, 0x0F),	\
49 												\
50   LINEFN_B(die, bpp8, 0x10), LINEFN_B(die, bpp8, 0x11), LINEFN_B(die, bpp8, 0x12), LINEFN_B(die, bpp8, 0x13),	\
51   LINEFN_B(die, bpp8, 0x14), LINEFN_B(die, bpp8, 0x15), LINEFN_B(die, bpp8, 0x16), LINEFN_B(die, bpp8, 0x17),	\
52   LINEFN_B(die, bpp8, 0x18), LINEFN_B(die, bpp8, 0x19), LINEFN_B(die, bpp8, 0x1A), LINEFN_B(die, bpp8, 0x1B),	\
53   LINEFN_B(die, bpp8, 0x1C), LINEFN_B(die, bpp8, 0x1D), LINEFN_B(die, bpp8, 0x1E), LINEFN_B(die, bpp8, 0x1F),	\
54  }
55 
56  {
57   LINEFN_BPP8(false, 0),
58   LINEFN_BPP8(false, 1),
59   LINEFN_BPP8(false, 2),
60  },
61  {
62   LINEFN_BPP8(true, 0),
63   LINEFN_BPP8(true, 1),
64   LINEFN_BPP8(true, 2),
65  }
66 
67 
68  #undef LINEFN_BPP8
69  #undef LINEFN_B
70  #undef LINEFN_BC
71 };
72 
RESUME_Line(const uint16 * cmd_data)73 int32 RESUME_Line(const uint16* cmd_data)
74 {
75  const uint16 mode = cmd_data[0x2];
76  // Abusing the SPD bit passed to the line draw function to denote non-transparency when == 1, transparent when == 0.
77  const bool SPD_Opaque = (((mode >> 3) & 0x7) < 0x6) ? ((int32)(TexFetchTab[(mode >> 3) & 0x1F](0xFFFFFFFF)) >= 0) : true;
78  auto* const fnptr = LineFuncTab[(bool)(FBCR & FBCR_DIE)][(TVMR & TVMR_8BPP) ? ((TVMR & TVMR_ROTATE) ? 2 : 1) : 0][((mode >> 6) & 0x1E) | SPD_Opaque /*(mode >> 6) & 0x1F*/][(mode & 0x8000) ? 8 : (mode & 0x7)];
79  const uint32 num_lines = (cmd_data[0] & 0x1) ? 4 : 1;
80  uint32 iter = PrimData.iter;
81  int32 ret = 0;
82 
83  if(MDFN_UNLIKELY(PrimData.need_line_resume))
84  {
85   PrimData.need_line_resume = false;
86   goto ResumeLine;
87  }
88 
89  if(iter < num_lines)
90  {
91   do
92   {
93    LineData.p[0].x = sign_x_to_s32(13, cmd_data[0x6 + (((iter << 1) + 0) & 0x7)] & 0x1FFF) + LocalX;
94    LineData.p[0].y = sign_x_to_s32(13, cmd_data[0x7 + (((iter << 1) + 0) & 0x7)] & 0x1FFF) + LocalY;
95    LineData.p[1].x = sign_x_to_s32(13, cmd_data[0x6 + (((iter << 1) + 2) & 0x7)] & 0x1FFF) + LocalX;
96    LineData.p[1].y = sign_x_to_s32(13, cmd_data[0x7 + (((iter << 1) + 2) & 0x7)] & 0x1FFF) + LocalY;
97 
98    if(mode & 0x4) // Gouraud
99    {
100     const uint16* gtb = &VRAM[cmd_data[0xE] << 2];
101 
102     ret += 2;
103     LineData.p[0].g = gtb[(iter + 0) & 0x3];
104     LineData.p[1].g = gtb[(iter + 1) & 0x3];
105    }
106 
107    SetupDrawLine(&ret, false, false, mode);
108    //
109    ResumeLine:;
110    ret += AdjustDrawTiming(fnptr(&PrimData.need_line_resume));
111    if(MDFN_UNLIKELY(PrimData.need_line_resume))
112     break;
113   } while(++iter < num_lines && ret < VDP1_SuspendResumeThreshold);
114  }
115 
116  PrimData.iter = iter;
117 
118  return ret;
119 }
120 
CMD_Line(const uint16 * cmd_data)121 int32 CMD_Line(const uint16* cmd_data)
122 {
123  int32 ret = 1;
124  //
125  //
126  LineData.tex_base = 0;
127  LineData.color = cmd_data[0x3];
128  //
129  //
130  PrimData.iter = 0;
131  PrimData.need_line_resume = false;
132 
133  return ret;
134 }
135 
136 }
137 
138 }
139