From a5be55369c11e8820fd0126c30ab0a554982fa2d Mon Sep 17 00:00:00 2001
From: johns <>
Date: Mon, 25 Mar 2002 00:52:34 +0000
Subject: [PATCH] Shared palette functions added.

---
 src/video/video.cpp | 173 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 140 insertions(+), 33 deletions(-)

diff --git a/src/video/video.cpp b/src/video/video.cpp
index 49a9698b6..06e3013db 100644
--- a/src/video/video.cpp
+++ b/src/video/video.cpp
@@ -10,12 +10,11 @@
 //
 /**@name video.c	-	The universal video functions. */
 //
-//	(c) Copyright 1999-2001 by Lutz Sammer
+//	(c) Copyright 1999-2002 by Lutz Sammer
 //
 //	FreeCraft is free software; you can redistribute it and/or modify
 //	it under the terms of the GNU General Public License as published
-//	by the Free Software Foundation; either version 2 of the License,
-//	or (at your option) any later version.
+//	by the Free Software Foundation; only version 2 of the License.
 //
 //	FreeCraft is distributed in the hope that it will be useful,
 //	but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -38,7 +37,7 @@
 **
 **
 **      @subsection VideoMain Video main initialization
-**		
+**
 **              The general setup of platform dependent video and basic video
 **		functionalities is done with function @see InitVideo
 **
@@ -67,7 +66,7 @@
 **		dependent settings/functionailty are located within each
 **		separate files:
 **
-**		X11 		: Xwindows for Linux and other Unix machines
+**		X11		: Xwindows for Linux and other Unix machines
 **
 **		SVGALIB		: (Super) Vga routines for Linux only
 **				  (visit http://www.svgalib.org)
@@ -214,8 +213,8 @@ global int VideoBpp;
     /**
     **  Architecture-dependant video memory-size (byte pro pixel).
     **  Set by InitVideo. (1,2,3,4 equals VideoBpp/8)
-    **  @see InitVideo 
-    */  
+    **  @see InitVideo
+    */
 global int VideoTypeSize;
 
     /**
@@ -241,6 +240,8 @@ global volatile int VideoInterrupts;	/// be happy, were are quicker
 global Palette GlobalPalette[256];
 
     /**
+    ** FIXME: this docu is added only to the first variable!
+    **
     **  As a video 8bpp pixel color doesn't have RGB encoded, but denote some
     **  index (a value from contents Pixels) in a system pallete, the
     **  following precalculated arrays deliver a shortcut.
@@ -250,29 +251,34 @@ global Palette GlobalPalette[256];
     **  The single main color palette denoting all possible colors on which all
     **  other palettes (including above GlobalPalette) are based.
     **  Note:this means other palettes probably doesn't contains unique colors.
-    **  
+    **
     **  commonpalette_defined:
     **  Denotes the defined entries (as bit index) in above palette.
     **  Needed as for X11 it is possible we can't get all 256 colors.
-    **  
+    **
     **  colorcube8:
     **  Array of 32*32*32 system colors, to get from an unsigned int RGB
     **  (5x5x5 bit) to a system color.
-    **  
+    **
     **  lookup25trans8:
     **  Array to get from two system colors as unsigned int (color1<<8)|color2
     **  to a new system color which is aproximately 75% color1 and 25% color2.
     **  lookup50trans8:
     **  The same for 50% color1 and 50% color2.
-    **  
+    **
     **  VideoAllocPalette8:
     **  Funcytion to let hardware independent palette be converted (when set).
     */
-global Palette   *commonpalette    = NULL;
+global Palette   *commonpalette;
+    // FIXME: docu
 global unsigned long commonpalette_defined[8];
-global VMemType8 *colorcube8       = NULL;
-global VMemType8 *lookup25trans8   = NULL;
-global VMemType8 *lookup50trans8   = NULL;
+    // FIXME: docu
+global VMemType8 *colorcube8;
+    // FIXME: docu
+global VMemType8 *lookup25trans8;
+    // FIXME: docu
+global VMemType8 *lookup50trans8;
+    // FIXME: docu
 global void (*VideoAllocPalette8)( Palette *palette,
                                    Palette *syspalette,
                                    unsigned long syspalette_defined[8] )=NULL;
@@ -280,7 +286,6 @@ global void (*VideoAllocPalette8)( Palette *palette,
     /// Does ColorCycling..
 global void (*ColorCycle)(void);
 
-
 /*----------------------------------------------------------------------------
 --	Functions
 ----------------------------------------------------------------------------*/
@@ -369,6 +374,108 @@ global void PopClipping(void)
     }
 }
 
+/**
+**	Creates a checksum used to compare palettes.
+**	JOSH: change the method if you have better ideas.
+**	JOHNS: I say this also always :)
+**
+**	@param palette	Palette source.
+**
+**	@return		Calculated hash/checksum.
+*/
+local long GetPaletteChecksum(const Palette* palette)
+{
+    long retVal;
+    int i;
+
+    for(retVal = i = 0; i < 256; i++){
+	//This is designed to return different values if
+	// the pixels are in a different order.
+	retVal = ((palette[i].r+i)&0xff)+retVal;
+	retVal = ((palette[i].g+i)&0xff)+retVal;
+	retVal = ((palette[i].b+i)&0xff)+retVal;
+    }
+    return retVal;
+}
+
+/**
+**	Creates a shared hardware palette from an independend Palette struct.
+**
+**	@param palette	System independend RGB palette structure.
+**
+**	@return		A palette in hardware  dependend format.
+*/
+global VMemType* VideoCreateSharedPalette(const Palette* palette)
+{
+    PaletteLink* current_link;
+    PaletteLink** prev_link;
+    VMemType* pixels;
+    long checksum;
+
+    pixels = VideoCreateNewPalette(palette);
+    checksum = GetPaletteChecksum(palette);
+    prev_link = &PaletteList;
+    while ((current_link=*prev_link)) {
+	if (current_link->Checksum == checksum
+		&& !memcmp(current_link->Palette,pixels,
+		    256*((VideoDepth+7)/8)) ) {
+	    break;
+	}
+	prev_link = &current_link->Next;
+    }
+
+    if (current_link) {			// Palette found (reuse)
+	free(pixels);
+	pixels = current_link->Palette;
+	++current_link->RefCount;
+	DebugLevel3("uses palette %p %d\n",pixels,current_link->RefCount);
+    } else {				// Palette NOT found
+	DebugLevel3("loading new palette %p\n",pixels);
+
+	current_link = *prev_link = malloc(sizeof(PaletteLink));
+	current_link->Checksum = checksum;
+	current_link->Next = NULL;
+	current_link->Palette = pixels;
+	current_link->RefCount = 1;
+    }
+
+    return pixels;
+}
+
+/**
+**	Free a shared hardware palette.
+**
+**	@param pixel	palette in hardware dependend format
+*/
+global void VideoFreeSharedPalette(VMemType* pixels)
+{
+    PaletteLink* current_link;
+    PaletteLink** prev_link;
+
+//    if( pixels==Pixels ) {
+//	DebugLevel3Fn("Freeing global palette\n");
+//    }
+
+    //
+    //  Find and free palette.
+    //
+    prev_link = &PaletteList;
+    while ((current_link = *prev_link)) {
+	if (current_link->Palette == pixels) {
+	    break;
+	}
+	prev_link = &current_link->Next;
+    }
+    if (current_link) {
+	if (!--current_link->RefCount) {
+	    DebugLevel3Fn("Free palette %p\n",pixels);
+	    free(current_link->Palette);
+	    *prev_link = current_link->Next;
+	    free(current_link);
+	}
+    }
+}
+
 /**
 **	Load a picture and display it on the screen (full screen),
 **	changing the colormap and so on..
@@ -377,22 +484,22 @@ global void PopClipping(void)
 */
 global void DisplayPicture(const char *name)
 {
-    Graphic* title;
+    Graphic* picture;
 
-    title=LoadGraphic(name);
-    VideoSetPalette(title->Pixels);
+    picture=LoadGraphic(name);
+    VideoSetPalette(picture->Pixels);
 
     VideoLockScreen();
 
     // FIXME: bigger window ?
-    VideoDrawSubClip(title,0,0
-	,title->Width,title->Height
-	,(VideoWidth-title->Width)/2,(VideoHeight-title->Height)/2);
+    VideoDrawSubClip(picture,0,0
+	,picture->Width,picture->Height
+	,(VideoWidth-picture->Width)/2,(VideoHeight-picture->Height)/2);
 
     VideoUnlockScreen();
 
-    VideoFree(title);
-    // FIXME: (ARI:) New Palette got stuck in memory?
+    VideoSetPalette(NULL);
+    VideoFree(picture);
 }
 
 /**
@@ -467,8 +574,9 @@ local void ColorCycle8(void)
     VMemType8 *pixels;
 
     if (ColorCycleAll) {
-	PaletteLink *current_link = PaletteList;
+	PaletteLink* current_link;
 
+	current_link = PaletteList;
 	while (current_link != NULL) {
 	    x = ((VMemType8 *) (current_link->Palette))[38];
 	    for (i = 38; i < 47; ++i) {	// tileset color cycle
@@ -527,8 +635,9 @@ local void ColorCycle16(void)
     VMemType16 *pixels;
 
     if (ColorCycleAll) {
-	PaletteLink *current_link = PaletteList;
+	PaletteLink* current_link;
 
+	current_link = PaletteList;
 	while (current_link != NULL) {
 	    x = ((VMemType16 *) (current_link->Palette))[38];
 	    for (i = 38; i < 47; ++i) {	// tileset color cycle
@@ -587,8 +696,9 @@ local void ColorCycle24(void)
     VMemType24 *pixels;
 
     if (ColorCycleAll) {
-	PaletteLink *current_link = PaletteList;
+	PaletteLink* current_link;
 
+	current_link = PaletteList;
 	while (current_link != NULL) {
 	    x = ((VMemType24 *) (current_link->Palette))[38];
 	    for (i = 38; i < 47; ++i) {	// tileset color cycle
@@ -647,8 +757,9 @@ local void ColorCycle32(void)
     VMemType32 *pixels;
 
     if (ColorCycleAll) {
-	PaletteLink *current_link = PaletteList;
+	PaletteLink* current_link;
 
+	current_link = PaletteList;
 	while (current_link != NULL) {
 	    x = ((VMemType32 *) (current_link->Palette))[38];
 	    for (i = 38; i < 47; ++i) { // tileset color cycle
@@ -1033,11 +1144,7 @@ local void InitSingleCommonPalette8( void )
 */
 global void VideoSetPalette(const VMemType* palette)
 {
-#if 0	// ARI: FIXME: This ruins menu palettes, when loaded via default.cm (introduce refcnt?)
-    if( Pixels ) {
-	free(Pixels);//FIXME: free unsufficient, XFreeColors needed for X11
-    }
-#endif
+    DebugLevel3Fn("Palette %x used\n",(unsigned)palette);
 
     Pixels=(VMemType*)palette;
     SetPlayersPalette();