diff --git a/src/m_anigif.c b/src/m_anigif.c
index 83bc3dddc0d46a682fa3df8863caf0a841de5c04..8113e20d8dd4231d606d8e986d5f025684e1bc11 100644
--- a/src/m_anigif.c
+++ b/src/m_anigif.c
@@ -505,14 +505,14 @@ static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr)
 	size_t src = 0, dest = 0;
 	size_t size = (vid.width * vid.height * 3);
 
-	InitColorLUT(gif_framepalette);
+	InitColorLUT(gif_framepalette, true);
 
 	while (src < size)
 	{
 		r = (UINT8)linear[src];
 		g = (UINT8)linear[src + 1];
 		b = (UINT8)linear[src + 2];
-		scr[dest] = colorlookup[r >> SHIFTCOLORBITS][g >> SHIFTCOLORBITS][b >> SHIFTCOLORBITS];
+		scr[dest] = GetColorLUTDirect(r, g, b);
 		src += (3 * scrbuf_downscaleamt);
 		dest += scrbuf_downscaleamt;
 	}
diff --git a/src/v_video.c b/src/v_video.c
index b88c4838bc4c66a74ddff5c008dfdf0051da26cc..3ac694dd45c417ffb344d2f417779b54d5331f33 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -3666,28 +3666,53 @@ Unoptimized version
 #endif
 }
 
-// Generates a color look-up table
-// which has up to 64 colors at each channel
-// (see the defines in v_video.h)
+// Generates a RGB565 color look-up table
+static colorlookup_t colorlookup;
 
-UINT8 colorlookup[CLUTSIZE][CLUTSIZE][CLUTSIZE];
-
-void InitColorLUT(RGBA_t *palette)
+void InitColorLUT(RGBA_t *palette, boolean makecolors)
 {
-	UINT8 r, g, b;
-	static boolean clutinit = false;
-	static RGBA_t *lastpalette = NULL;
-	if ((!clutinit) || (lastpalette != palette))
+	size_t palsize = (sizeof(RGBA_t) * 256);
+
+	if (!colorlookup.init || memcmp(colorlookup.palette, palette, palsize))
 	{
-		for (r = 0; r < CLUTSIZE; r++)
-			for (g = 0; g < CLUTSIZE; g++)
-				for (b = 0; b < CLUTSIZE; b++)
-					colorlookup[r][g][b] = NearestPaletteColor(r << SHIFTCOLORBITS, g << SHIFTCOLORBITS, b << SHIFTCOLORBITS, palette);
-		clutinit = true;
-		lastpalette = palette;
+		INT32 i;
+
+		colorlookup.init = true;
+		memcpy(colorlookup.palette, palette, palsize);
+
+		for (i = 0; i < 0xFFFF; i++)
+			colorlookup.table[i] = 0xFFFF;
+
+		if (makecolors)
+		{
+			UINT8 r, g, b;
+
+			for (r = 0; r < 0xFF; r++)
+			for (g = 0; g < 0xFF; g++)
+			for (b = 0; b < 0xFF; b++)
+			{
+				i = CLUTINDEX(r, g, b);
+				if (colorlookup.table[i] == 0xFFFF)
+					colorlookup.table[i] = NearestPaletteColor(r, g, b, palette);
+			}
+		}
 	}
 }
 
+UINT8 GetColorLUT(UINT8 r, UINT8 g, UINT8 b)
+{
+	INT32 i = CLUTINDEX(r, g, b);
+	if (colorlookup.table[i] == 0xFFFF)
+		colorlookup.table[i] = NearestPaletteColor(r << 3, g << 2, b << 3, colorlookup.palette);
+	return colorlookup.table[i];
+}
+
+UINT8 GetColorLUTDirect(UINT8 r, UINT8 g, UINT8 b)
+{
+	INT32 i = CLUTINDEX(r, g, b);
+	return colorlookup.table[i];
+}
+
 // V_Init
 // old software stuff, buffers are allocated at video mode setup
 // here we set the screens[x] pointers accordingly
diff --git a/src/v_video.h b/src/v_video.h
index 9f7a9a9e9c29dd8fb23ecfbfb4d1d09d1d7cba8d..6cd10f606c5da51e7b11b5612d7ff039991c9543 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -38,13 +38,18 @@ cv_allcaps;
 void V_Init(void);
 
 // Color look-up table
-#define COLORBITS 6
-#define SHIFTCOLORBITS (8-COLORBITS)
-#define CLUTSIZE (1<<COLORBITS)
-
-extern UINT8 colorlookup[CLUTSIZE][CLUTSIZE][CLUTSIZE];
-
-void InitColorLUT(RGBA_t *palette);
+#define CLUTINDEX(r, g, b) (((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3)
+
+void InitColorLUT(RGBA_t *palette, boolean makecolors);
+UINT8 GetColorLUT(UINT8 r, UINT8 g, UINT8 b);
+UINT8 GetColorLUTDirect(UINT8 r, UINT8 g, UINT8 b);
+
+typedef struct
+{
+	boolean init;
+	RGBA_t palette[256];
+	UINT16 table[0xFFFF];
+} colorlookup_t;
 
 // Set the current RGB palette lookup to use for palettized graphics
 void V_SetPalette(INT32 palettenum);