643c6e06ed7da963a1bb219b0d0da6dd0cc225b4
[pcsx_rearmed.git] / plugins / gpu_unai / gpu_inner_light.h
1 /***************************************************************************
2 *   Copyright (C) 2016 PCSX4ALL Team                                      *
3 *   Copyright (C) 2010 Unai                                               *
4 *                                                                         *
5 *   This program is free software; you can redistribute it and/or modify  *
6 *   it under the terms of the GNU General Public License as published by  *
7 *   the Free Software Foundation; either version 2 of the License, or     *
8 *   (at your option) any later version.                                   *
9 *                                                                         *
10 *   This program is distributed in the hope that it will be useful,       *
11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13 *   GNU General Public License for more details.                          *
14 *                                                                         *
15 *   You should have received a copy of the GNU General Public License     *
16 *   along with this program; if not, write to the                         *
17 *   Free Software Foundation, Inc.,                                       *
18 *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
19 ***************************************************************************/
20
21 #ifndef _OP_LIGHT_H_
22 #define _OP_LIGHT_H_
23
24 //  GPU color operations for lighting calculations
25
26 static void SetupLightLUT()
27 {
28         // 1024-entry lookup table that modulates 5-bit texture + 5-bit light value.
29         // A light value of 15 does not modify the incoming texture color.
30         // LightLUT[32*32] array is initialized to following values:
31         //  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
32         //  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
33         //  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
34         //  0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
35         //  0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
36         //  0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9,
37         //  0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9,10,10,10,11,11,
38         //  0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 7, 8, 8, 9, 9,10,10,10,11,11,12,12,13,13,
39         //  0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13,13,14,14,15,15,
40         //  0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, 9, 9,10,10,11,11,12,12,13,14,14,15,15,16,16,17,
41         //  0, 0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9,10,10,11,11,12,13,13,14,15,15,16,16,17,18,18,19,
42         //  0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9,10,11,11,12,13,13,14,15,15,16,17,17,18,19,19,20,21,
43         //  0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9,10,11,12,12,13,14,15,15,16,17,18,18,19,20,21,21,22,23,
44         //  0, 0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 8, 9,10,11,12,13,13,14,15,16,17,17,18,19,20,21,21,22,23,24,25,
45         //  0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9,10,11,12,13,14,14,15,16,17,18,19,20,21,21,22,23,24,25,26,27,
46         //  0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,
47         //  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
48         //  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,31,
49         //  0, 1, 2, 3, 4, 5, 6, 7, 9,10,11,12,13,14,15,16,18,19,20,21,22,23,24,25,27,28,29,30,31,31,31,31,
50         //  0, 1, 2, 3, 4, 5, 7, 8, 9,10,11,13,14,15,16,17,19,20,21,22,23,24,26,27,28,29,30,31,31,31,31,31,
51         //  0, 1, 2, 3, 5, 6, 7, 8,10,11,12,13,15,16,17,18,20,21,22,23,25,26,27,28,30,31,31,31,31,31,31,31,
52         //  0, 1, 2, 3, 5, 6, 7, 9,10,11,13,14,15,17,18,19,21,22,23,24,26,27,28,30,31,31,31,31,31,31,31,31,
53         //  0, 1, 2, 4, 5, 6, 8, 9,11,12,13,15,16,17,19,20,22,23,24,26,27,28,30,31,31,31,31,31,31,31,31,31,
54         //  0, 1, 2, 4, 5, 7, 8,10,11,12,14,15,17,18,20,21,23,24,25,27,28,30,31,31,31,31,31,31,31,31,31,31,
55         //  0, 1, 3, 4, 6, 7, 9,10,12,13,15,16,18,19,21,22,24,25,27,28,30,31,31,31,31,31,31,31,31,31,31,31,
56         //  0, 1, 3, 4, 6, 7, 9,10,12,14,15,17,18,20,21,23,25,26,28,29,31,31,31,31,31,31,31,31,31,31,31,31,
57         //  0, 1, 3, 4, 6, 8, 9,11,13,14,16,17,19,21,22,24,26,27,29,30,31,31,31,31,31,31,31,31,31,31,31,31,
58         //  0, 1, 3, 5, 6, 8,10,11,13,15,16,18,20,21,23,25,27,28,30,31,31,31,31,31,31,31,31,31,31,31,31,31,
59         //  0, 1, 3, 5, 7, 8,10,12,14,15,17,19,21,22,24,26,28,29,31,31,31,31,31,31,31,31,31,31,31,31,31,31,
60         //  0, 1, 3, 5, 7, 9,10,12,14,16,18,19,21,23,25,27,29,30,31,31,31,31,31,31,31,31,31,31,31,31,31,31,
61         //  0, 1, 3, 5, 7, 9,11,13,15,16,18,20,22,24,26,28,30,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,
62         //  0, 1, 3, 5, 7, 9,11,13,15,17,19,21,23,25,27,29,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
63
64         for (int j=0; j < 32; ++j) {
65                 for (int i=0; i < 32; ++i) {
66                         int val = i * j / 16;
67                         if (val > 31) val = 31;
68                         gpu_unai.LightLUT[(j*32) + i] = val;
69                 }
70         }
71 }
72
73 // gcc5+ and clang13+ understarnd this on ARM
74 GPU_INLINE s32 clamp_c(s32 x) {
75     if (x < 0) return 0;
76     if (x > 31) return 31;
77     return x;
78 }
79
80 ////////////////////////////////////////////////////////////////////////////////
81 // Create packed Gouraud fixed-pt 8.8 rgb triplet
82 //
83 // INPUT:
84 // 'r','g','b' are 8.10 fixed-pt color components (r shown here)
85 //     'r' input:  --------------rrrrrrrrXXXXXXXXXX
86 //                 ^ bit 31
87 // RETURNS:
88 //    gcol_t output:  ccccccccXXXXXXXX for c in [r, g, b]
89 //                    ^ bit 16
90 // Where 'r,g,b' are integer bits of colors, 'X' fixed-pt, and '-' don't care
91 ////////////////////////////////////////////////////////////////////////////////
92 GPU_INLINE gcol_t gpuPackGouraudCol(u32 r, u32 g, u32 b)
93 {
94         return (gcol_t){{
95                 (u16)(r >> 2),
96                 (u16)(g >> 2),
97                 (u16)(b >> 2),
98                 0
99         }};
100 }
101
102 ////////////////////////////////////////////////////////////////////////////////
103 // Create packed increment for Gouraud fixed-pt 8.8 rgb triplet
104 //
105 // INPUT:
106 //  Sign-extended 8.10 fixed-pt r,g,b color increment values (only dr is shown)
107 //   'dr' input:  ssssssssssssssrrrrrrrrXXXXXXXXXX
108 //                ^ bit 31
109 // RETURNS:
110 //   gcol_t output:  ccccccccXXXXXXXX for c in [r, g, b]
111 //                   ^ bit 16
112 // Where 'r,g,b' are integer bits of colors, 'X' fixed-pt, and 's' sign bits
113 //
114 // NOTE: The correctness of this code/method has not been fully verified,
115 //       having been merely factored out from original code in
116 //       poly-drawing functions. Feel free to check/improve it -senquack
117 ////////////////////////////////////////////////////////////////////////////////
118 GPU_INLINE gcol_t gpuPackGouraudColInc(s32 dr, s32 dg, s32 db)
119 {
120         return (gcol_t){{
121                 (u16)((dr >> 2) + (dr < 0)),
122                 (u16)((dg >> 2) + (dg < 0)),
123                 (u16)((db >> 2) + (db < 0)),
124                 0
125         }};
126 }
127
128 ////////////////////////////////////////////////////////////////////////////////
129 // Extract bgr555 color from Gouraud u32 fixed-pt 8.8 rgb triplet
130 //
131 // INPUT:
132 //  'gCol' input:  ccccccccXXXXXXXX for c in [r, g, b]
133 //                 ^ bit 16
134 // RETURNS:
135 //    u16 output:  0bbbbbgggggrrrrr
136 //                 ^ bit 16
137 // Where 'r,g,b' are integer bits of colors, 'X' fixed-pt, and '0' zero
138 ////////////////////////////////////////////////////////////////////////////////
139 GPU_INLINE uint_fast16_t gpuLightingRGB(gcol_t gCol)
140 {
141         return (gCol.c.r >> 11) |
142                 ((gCol.c.g >> 6) & 0x3e0) |
143                 ((gCol.c.b >> 1) & 0x7c00);
144 }
145
146 GPU_INLINE uint_fast16_t gpuLightingRGBDither(gcol_t gCol, int_fast16_t dt)
147 {
148         dt <<= 4;
149         return  clamp_c(((s32)gCol.c.r + dt) >> 11) |
150                (clamp_c(((s32)gCol.c.g + dt) >> 11) << 5) |
151                (clamp_c(((s32)gCol.c.b + dt) >> 11) << 10);
152 }
153
154 ////////////////////////////////////////////////////////////////////////////////
155 // Apply fast (low-precision) 5-bit lighting to bgr555 texture color:
156 //
157 // INPUT:
158 //        'r8','g8','b8' are unsigned 8-bit color values, value of 127
159 //          is midpoint that doesn't modify that component of texture
160 //        'uSrc' input:  mbbbbbgggggrrrrr
161 //                       ^ bit 16
162 // RETURNS:
163 //          u16 output:  mbbbbbgggggrrrrr
164 // Where 'X' are fixed-pt bits, 'm' is the MSB to preserve
165 ////////////////////////////////////////////////////////////////////////////////
166 GPU_INLINE uint_fast16_t gpuLightingTXTGeneric(uint_fast16_t uSrc, u32 bgr0888)
167 {
168         // the compiler can move this out of the loop if it wants to
169         uint_fast32_t b5 = (bgr0888 >> 19);
170         uint_fast32_t g5 = (bgr0888 >> 11) & 0x1f;
171         uint_fast32_t r5 = (bgr0888 >>  3) & 0x1f;
172
173         return (gpu_unai.LightLUT[((uSrc&0x7C00)>>5) | b5] << 10) |
174                (gpu_unai.LightLUT[ (uSrc&0x03E0)     | g5] <<  5) |
175                (gpu_unai.LightLUT[((uSrc&0x001F)<<5) | r5]      ) |
176                (uSrc & 0x8000);
177 }
178
179
180 ////////////////////////////////////////////////////////////////////////////////
181 // Apply fast (low-precision) 5-bit Gouraud lighting to bgr555 texture color:
182 //
183 // INPUT:
184 //  'gCol' is a Gouraud fixed-pt 8.8 rgb triplet
185 //        'gCol' input:  ccccccccXXXXXXXX for c in [r, g, b]
186 //                       ^ bit 16
187 //        'uSrc' input:  mbbbbbgggggrrrrr
188 //                       ^ bit 16
189 // RETURNS:
190 //          u16 output:  mbbbbbgggggrrrrr
191 // Where 'X' are fixed-pt bits, 'm' is the MSB to preserve
192 ////////////////////////////////////////////////////////////////////////////////
193 GPU_INLINE uint_fast16_t gpuLightingTXTGouraudGeneric(uint_fast16_t uSrc, gcol_t gCol)
194 {
195         return (gpu_unai.LightLUT[((uSrc&0x7C00)>>5) | (gCol.c.b >> 11)] << 10) |
196                (gpu_unai.LightLUT[ (uSrc&0x03E0)     | (gCol.c.g >> 11)] << 5) |
197                (gpu_unai.LightLUT[((uSrc&0x001F)<<5) | (gCol.c.r >> 11)]) |
198                (uSrc & 0x8000);
199 }
200
201 ////////////////////////////////////////////////////////////////////////////////
202 // Apply high-precision 8-bit lighting to bgr555 texture color,
203 //
204 // INPUT:
205 //        'r','g','b' are unsigned 8-bit color component values, value of
206 //          127 is midpoint that doesn't modify that component of texture
207 //
208 //         uSrc input: mbbbbbgggggrrrrr
209 //                     ^ bit 16
210 // RETURNS:
211 //        u16 output:  mbbbbbgggggrrrrr
212 // Where 'X' are fixed-pt bits, 'm' is the MSB to preserve
213 ////////////////////////////////////////////////////////////////////////////////
214 GPU_INLINE uint_fast16_t gpuLightingTXTDitherRGB(uint_fast16_t uSrc,
215         uint_fast8_t r, uint_fast8_t g, uint_fast8_t b, int_fast16_t dv)
216 {
217         uint_fast16_t rs = uSrc & 0x001F;
218         uint_fast16_t gs = uSrc & 0x03E0;
219         uint_fast16_t bs = uSrc & 0x7C00;
220         s32 r3 = rs * r +  dv;
221         s32 g3 = gs * g + (dv << 5);
222         s32 b3 = bs * b + (dv << 10);
223         return  clamp_c(r3 >> 7) |
224                (clamp_c(g3 >> 12) << 5) |
225                (clamp_c(b3 >> 17) << 10) |
226                (uSrc & 0x8000);
227 }
228
229 GPU_INLINE uint_fast16_t gpuLightingTXTDither(uint_fast16_t uSrc, u32 bgr0888, int_fast16_t dv)
230 {
231         return gpuLightingTXTDitherRGB(uSrc, bgr0888 & 0xff,
232                         (bgr0888 >> 8) & 0xff, bgr0888 >> 16, dv);
233 }
234
235 GPU_INLINE uint_fast16_t gpuLightingTXTGouraudDither(uint_fast16_t uSrc, gcol_t gCol, int_fast8_t dv)
236 {
237         return gpuLightingTXTDitherRGB(uSrc, gCol.c.r >> 8, gCol.c.g >> 8, gCol.c.b >> 8, dv);
238 }
239
240 #endif  //_OP_LIGHT_H_