summaryrefslogtreecommitdiff
path: root/tools/generate_cc_lut.c
blob: 33b4cef0d1e0bf47ed426c30d14dae1bfa3d730a (plain)
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <stdio.h>
#include <stdint.h>
#include <math.h>

/* gpsp targets devices that are too slow to generate
 * a colour correction table at runtime. We therefore
 * have to pre-generate the lookup table array... */

/* Colour correction defines */
#define CC_TARGET_GAMMA   2.2f
#define CC_RGB_MAX       31.0f
#define CC_LUM            0.94f
#define CC_R              0.82f
#define CC_G              0.665f
#define CC_B              0.73f
#define CC_RG             0.125f
#define CC_RB             0.195f
#define CC_GR             0.24f
#define CC_GB             0.075f
#define CC_BR            -0.06f
#define CC_BG             0.21f
#define CC_GAMMA_ADJ      1.0f

/* Output video is RGB565. This is 16bit,
 * but only 15 bits are actually used
 * (i.e. 'G' is the highest 5 bits of the
 * 6bit component). To save memory, we
 * only include 15bit compound values
 * and convert RGB565 video to 15bit when
 * using the lookup table */
#define CC_LUT_SIZE       32768

static uint16_t c_lut[CC_LUT_SIZE] = {0};

void init_lut(void)
{
   size_t color;
   float display_gamma_inv = 1.0f / CC_TARGET_GAMMA;
   float rgb_max_inv       = 1.0f / CC_RGB_MAX;
   float adjusted_gamma    = CC_TARGET_GAMMA + CC_GAMMA_ADJ;

   /* Populate colour correction look-up table */
   for (color = 0; color < CC_LUT_SIZE; color++)
   {
      unsigned r_final = 0;
      unsigned g_final = 0;
      unsigned b_final = 0;
      /* Extract values from RGB555 input */
      const unsigned r = color >> 10 & 0x1F;
      const unsigned g = color >>  5 & 0x1F;
      const unsigned b = color       & 0x1F;
      /* Perform gamma expansion */
      float r_float = pow((float)r * rgb_max_inv, adjusted_gamma);
      float g_float = pow((float)g * rgb_max_inv, adjusted_gamma);
      float b_float = pow((float)b * rgb_max_inv, adjusted_gamma);
      /* Perform colour mangling */
      float r_correct = CC_LUM * ((CC_R  * r_float) + (CC_GR * g_float) + (CC_BR * b_float));
      float g_correct = CC_LUM * ((CC_RG * r_float) + (CC_G  * g_float) + (CC_BG * b_float));
      float b_correct = CC_LUM * ((CC_RB * r_float) + (CC_GB * g_float) + (CC_B  * b_float));
      /* Range check... */
      r_correct = r_correct > 0.0f ? r_correct : 0.0f;
      g_correct = g_correct > 0.0f ? g_correct : 0.0f;
      b_correct = b_correct > 0.0f ? b_correct : 0.0f;
      /* Perform gamma compression */
      r_correct = pow(r_correct, display_gamma_inv);
      g_correct = pow(g_correct, display_gamma_inv);
      b_correct = pow(b_correct, display_gamma_inv);
      /* Range check... */
      r_correct = r_correct > 1.0f ? 1.0f : r_correct;
      g_correct = g_correct > 1.0f ? 1.0f : g_correct;
      b_correct = b_correct > 1.0f ? 1.0f : b_correct;
      /* Convert to RGB565 */
      r_final = (unsigned)((r_correct * CC_RGB_MAX) + 0.5f) & 0x1F;
      g_final = (unsigned)((g_correct * CC_RGB_MAX) + 0.5f) & 0x1F;
      b_final = (unsigned)((b_correct * CC_RGB_MAX) + 0.5f) & 0x1F;
      c_lut[color] = r_final << 11 | g_final << 6 | b_final;
   }
}

int main(int argc, char *argv[])
{
   FILE *file = NULL;
   size_t i;

   /* Populate lookup table */
   init_lut();

   /* Write header file */
   file = fopen("../gba_cc_lut.h", "w");

   if (!file)
      return 1;

   fprintf(file,
         "#ifndef __CC_LUT_H__\n"
         "#define __CC_LUT_H__\n\n"
         "#include \"common.h\"\n\n"
         "extern const u16 gba_cc_lut[];\n\n"
         "#endif /* __CC_LUT_H__ */\n");

   fclose(file);
   file = NULL;

   /* Write source file */
   file = fopen("../gba_cc_lut.c", "w");

   if (!file)
      return 1;

   fprintf(file,
         "#include \"gba_cc_lut.h\"\n\n"
         "const u16 gba_cc_lut[] = {\n");

   for (i = 0; i < CC_LUT_SIZE; i++)
   {
      fprintf(file, " 0x%04x", c_lut[i]);

      if (i == CC_LUT_SIZE - 1)
         fprintf(file, "\n");
      else
      {
         if ((i + 1) % 5 == 0)
            fprintf(file, ",\n");
         else
            fprintf(file, ",");
      }
   }

   fprintf(file, "};\n");

   fclose(file);
   file = NULL;

   return 0;
}