/*****************************************************************************

        GRAOUMF TRACKER 2
        Author: Laurent de Soras, 1996-2016

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*****************************************************************************/



/*
Ne pas oublier de:
	- Faire une routine de changement des attributs d'un objet et de sa
	  descendance
*/



/*\\\ FICHIERS INCLUDE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include	<assert.h>
#include <stdio.h>
#include	<stdlib.h>
#include <time.h>
#include	<math.h>

#include "archi.h"
#include "base.h"
#include "base_ct.h"
#include "file.h"
#include	"Graphic.h"
#include "intrface.h"
#include	"log.h"
#include "memory.h"
#include "resource.h"
#include	"rsc01.h"
#include	"Skin.h"
#include "String.h"



/*\\\ CONSTANTES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ TYPES & STRUCTURES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ PROTOTYPES PRIVES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

signed int	RSC_load_misc_gfx (void);

void	RSC_display_object_recursive (int object, bool brother_flag, bool child_flag);
void	RSC_display_object_point (int pix_x, int pix_y, const RSC_OBJTYPE_POINT *objet_ptr);
void	RSC_display_object_hline (int pix_x, int pix_y, const RSC_OBJTYPE_HLINE *objet_ptr);
void	RSC_display_object_vline (int pix_x, int pix_y, const RSC_OBJTYPE_VLINE *objet_ptr);
void	RSC_display_object_box (int pix_x, int pix_y, const RSC_OBJTYPE_BOX *objet_ptr);
void	RSC_display_object_xorbox (int pix_x, int pix_y, const RSC_OBJTYPE_XORBOX *objet_ptr);
void	RSC_display_object_bitmap (int pix_x, int pix_y, const RSC_OBJTYPE_BITMAP *objet_ptr);
void	RSC_display_object_tbitmap (int pix_x, int pix_y, const RSC_OBJTYPE_TBITMAP *objet_ptr);
void	RSC_display_object_text (int pix_x, int pix_y, const RSC_OBJTYPE_TEXT *objet_ptr);
void	RSC_display_object_ttext (int pix_x, int pix_y, const RSC_OBJTYPE_TTEXT *objet_ptr);
void	RSC_display_object_intbox (int pix_x, int pix_y, const RSC_OBJTYPE_INTBOX *objet_ptr);
void	RSC_display_object_extbox (int pix_x, int pix_y, const RSC_OBJTYPE_EXTBOX *objet_ptr);
void	RSC_display_object_boxtext (int pix_x, int pix_y, const RSC_OBJTYPE_BOXTEXT *objet_ptr);
void	RSC_display_object_edboxtext (int pix_x, int pix_y, const RSC_OBJTYPE_EDBOXTEXT *objet_ptr);
void	RSC_display_object_button (int pix_x, int pix_y, const RSC_OBJTYPE_BUTTON *objet_ptr);
signed long	RSC_get_button_picture_nbr (const RSC_OBJTYPE_HEADER *object_ptr, int elt, bool &disable_flag, bool &selected_flag);
Image	*RSC_get_button_picture_ptr (const RSC_OBJTYPE_HEADER *object_ptr, int elt, bool &disable_flag, bool &selected_flag);
void	RSC_display_tiled_pic (const RSC_OBJTYPE_HEADER *object_ptr, const Skin_SpecialElt *elt_ptr, Graphic_FRAME_INFO *cadre_ptr, bool &disable_flag, bool ext_flag, bool fill_flag);



/*\\\ VARIABLES EXTERNES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

/* Chemin des fichiers des icones et images,
   relativement au chemin du programme. */
const char	RSC_pic_directory_0 [] = "gfx";

/* Nom du fichier graphique contenant la fonte */
const char	RSC_font_filename_0 [] = "font.pcx";

/* Support de skin */
Skin	*RSC_skin_ptr = NULL;

/* Images utilisees par l'interface */
int	RSC_gfx_nbr [RSC_GFX_TOTAL_NBR];

RSC_OBJTYPE_HEADER	*RSC_object_ptr [RSC_NBROBJECTS_MAXI+RSC_NBR_CUSTOM_OBJECTS];	/* Tableau de pointeurs sur les objets du fichier resource, a initialiser */
int	RSC_absolute_object_pixxpos [RSC_NBROBJECTS_MAXI+RSC_NBR_CUSTOM_OBJECTS];	/* Coordonnees x absolues de tous les objets */
int	RSC_absolute_object_pixypos [RSC_NBROBJECTS_MAXI+RSC_NBR_CUSTOM_OBJECTS];	/* Coordonnees y absolues de tous les objets */
clock_t	RSC_click_time_base;	/* Instant de debut de clic d'un objet */
clock_t	RSC_last_click_time;	/* Instant du dernier clic signale a l'utilisateur */

int	RSC_info_line_len = 79;		/* Longueur de la ligne d'info sans le 0 */

/* Sert a la routine de gestion du resource */
int	RSC_mem_object = -1;
int	RSC_mem_aine = -1;

int	RSC_mouse_key;	/* Bouton qui a ete utilise lors du clic sur un objet */



/*\\\ VARIABLES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ FONCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*==========================================================================*/
/*      Nom: RSC_init_resource                                              */
/*      Description: Initialise les resources.                              */
/*      Retour: 0 si tout s'est bien passe.                                 */
/*==========================================================================*/

signed int	RSC_init_resource (void)
{
	String	filename;

	/* Cree un support pour la skin */
	RSC_skin_ptr = new Skin (
		(FILE_program_pathname + RSC_pic_directory_0 + FILE_path_separator_0).c_str ()
	);
	if (RSC_skin_ptr == NULL)
	{
		LOG_printf ("RSC_init_resource: Error: couldn't init skin data.\n");
		return (-1);
	}

	/* Charge le fichier de resources */
	filename = FILE_program_pathname + RSC_RESOURCE_FILE_NAME;
	if (RSC_load_resource_file (filename.c_str ()) != 0)
	{
		LOG_printf ("RSC_init_resource: Error: couldn't load resource file.\n");
		return (-1);
	}
	RSC_set_absolute_object_position_rec (0, 0, 0, true);		/* Initialise les coordonnees des objets */

	/* Init des variable concernant le fichier resource */
	RSC_info_line_len = MIN (INTR_graph_ptr->get_width () / RSC_CHAR_W - 2,
	                         (int) strlen (RSC_get_string (RSC_OBJ_MP_INFLIN_TEXT)));

	/* Charge quelques images additionnelles */
	if (RSC_load_misc_gfx ())
	{
		LOG_printf ("RSC_init_resource: Error: couldn't load misc pictures.\n");
		return (-1);
	}

#if 0
	/* Chargement de la skin par defaut */
	if (RSC_skin_ptr->load_custom_skin (FILE_program_pathname + "default_skin" + FILE_path_separator_0))
	{
		LOG_printf ("RSC_init_resource: Error: couldn't load default skin.\n");
		return (-1);
	}
#endif

	/* Enregistre la fonte */
	if (INTR_graph_ptr->set_font (RSC_CHAR_W, RSC_CHAR_H,
	                              RSC_skin_ptr->get_pic_ptr (RSC_gfx_nbr [RSC_GFX_FONT])->get_data_ptr ()))
	{
		LOG_printf ("RSC_init_resource: Error: couldn't set font.\n");
		return (-1);
	}

	return (0);
}



void	RSC_restore_resource (void)
{
	int		object_cnt;
	RSC_OBJTYPE_HEADER	*object_ptr;

	for (object_cnt = 0; object_cnt < RSC_NBROBJECTS_MAXI+RSC_NBR_CUSTOM_OBJECTS; object_cnt ++)
	{
		if (RSC_object_ptr [object_cnt] != NULL)
		{
			object_ptr = RSC_object_ptr [object_cnt];
			switch (object_ptr->primitive)
			{
			case	RSC_OBJECT_NUMBER_TEXT:
				FREE (((RSC_OBJTYPE_TEXT *) object_ptr)->text_0);
				break;
			case	RSC_OBJECT_NUMBER_TTEXT:
				FREE (((RSC_OBJTYPE_TTEXT *) object_ptr)->text_0);
				break;
			case	RSC_OBJECT_NUMBER_BOXTEXT:
				FREE (((RSC_OBJTYPE_BOXTEXT *) object_ptr)->text_0);
				break;
			case	RSC_OBJECT_NUMBER_EDBOXTEXT:
				FREE (((RSC_OBJTYPE_EDBOXTEXT *) object_ptr)->text_0);
				break;
			}
			FREE (object_ptr);
			RSC_object_ptr [object_cnt] = NULL;
		}
	}

	if (RSC_skin_ptr != NULL)
	{
		delete RSC_skin_ptr;
		RSC_skin_ptr = NULL;
	}
}



signed int	RSC_load_misc_gfx (void)
{
	struct
	{
		int		nbr;
		const	char	*filename_0;
	} data [RSC_GFX_TOTAL_NBR] =
	{
		{ RSC_GFX_FONT,					RSC_font_filename_0 },
		{ RSC_GFX_VUMETRE_H_DARK,		"vumetre_h_dark.pcx" },
		{ RSC_GFX_VUMETRE_H_BRIGHT,	"vumetre_h_bright.pcx" },
		{ RSC_GFX_KNOB_1_H_G,			"knob_1_h_g.pcx" },
		{ RSC_GFX_KNOB_2_H_B,			"knob_2_h_b.pcx" },
		{ RSC_GFX_KNOB_2_V_B,			"knob_2_v_b.pcx" },
		{ RSC_GFX_PANMETRE_112,			"panmetre_112.pcx" }
	};

	for (int gfx = 0; gfx < RSC_GFX_TOTAL_NBR; gfx ++)
	{
		RSC_gfx_nbr [data [gfx].nbr] = RSC_skin_ptr->add_pic (data [gfx].filename_0, false);
		if (RSC_gfx_nbr [data [gfx].nbr] < 0)
		{
			LOG_printf ("RSC_load_misc_gfx: Error: couldn't load file \"%s\".\n",
			            data [gfx].filename_0);
			return (-1);
		}
	}

	return (0);
}



/*==========================================================================*/
/*      Nom: RSC_load_resource_file                                         */
/*      Description: Charge le fichier resource de l'interface.             */
/*      Parametres en entree:                                               */
/*        - filename_0: nom du fichier, avec son extension, avec ou sans    */
/*                      chemin ou lecteur.                                  */
/*      Retour: 0 si tout s'est bien passe.                                 */
/*==========================================================================*/

int	RSC_load_resource_file (const char *filename_0)
{
	FILE		*file_ptr;
	RSC_OBJTYPE_HEADER	header;
	RSC_OBJTYPE_HEADER	*object_ptr;
	int		parameter;
	int		object;
	char		buffer_0 [1023+1];
	int		nbr_strings;
	int		pic;
	String	picname;
	int		pic_array [3];

	LOG_printf ("RSC_load_resource_file:\n");

	/* Ouverture */
	file_ptr = FILE_fopen (filename_0, "rb");
	if (file_ptr == NULL)
	{
		LOG_printf ("RSC_load_resource_file: Error: couldn't open file.\n");
		return (-1);
	}

	/* Lecture */
	fscanf (file_ptr, "%s\n", buffer_0);
	if (strcmp (buffer_0, "GRAOUMF_TRACKER_resource_file") != 0)
	{
		LOG_printf ("RSC_load_resource_file: Error: %s is not a Graoumf Tracker resource file.\n", filename_0);
		fclose (file_ptr);
		return (-1);
	}

	nbr_strings = 0;
	for ( ; ; )
	{
		fscanf (file_ptr, "%s %d\n", buffer_0, &parameter);

		/* Objets */
		if (strcmp (buffer_0, "Object") == 0)
		{
			object = parameter;
			FILE_read_string_in_file (buffer_0, file_ptr);		/* Nom: on jette */
			fscanf (file_ptr, "%s\n", buffer_0);					/* Id: on jette */
			fscanf (file_ptr, "%d %ld %d %d %d %d\n",
						&header.primitive,
						&header.attributes,
						&header.child,
						&header.brother,
						&header.x,
						&header.y);
			object_ptr = (RSC_OBJTYPE_HEADER *) MALLOC (RSC_get_object_len (header.primitive));
			*object_ptr = header;
			RSC_object_ptr [object] = object_ptr;

			switch (object_ptr->primitive)
			{
			case	RSC_OBJECT_NUMBER_NULL:
				break;

			case	RSC_OBJECT_NUMBER_POINT:
				fscanf (file_ptr, "%d\n",
						  &((RSC_OBJTYPE_POINT *) object_ptr)->c);
				break;

			case	RSC_OBJECT_NUMBER_HLINE:
				fscanf (file_ptr, "%d %d\n",
						  &((RSC_OBJTYPE_HLINE *) object_ptr)->l,
						  &((RSC_OBJTYPE_HLINE *) object_ptr)->c);
				break;

			case	RSC_OBJECT_NUMBER_VLINE:
				fscanf (file_ptr, "%d %d\n",
						  &((RSC_OBJTYPE_VLINE *) object_ptr)->h,
						  &((RSC_OBJTYPE_VLINE *) object_ptr)->c);
				break;

			case	RSC_OBJECT_NUMBER_BOX:
				fscanf (file_ptr, "%d %d %d\n",
						  &((RSC_OBJTYPE_BOX *) object_ptr)->l,
						  &((RSC_OBJTYPE_BOX *) object_ptr)->h,
						  &((RSC_OBJTYPE_BOX *) object_ptr)->c);
				break;

			case	RSC_OBJECT_NUMBER_XORBOX:
				fscanf (file_ptr, "%d %d %d\n",
						  &((RSC_OBJTYPE_XORBOX *) object_ptr)->l,
						  &((RSC_OBJTYPE_XORBOX *) object_ptr)->h,
						  &((RSC_OBJTYPE_XORBOX *) object_ptr)->c);
				break;

			case	RSC_OBJECT_NUMBER_BITMAP:
				for (pic = 0; pic < 3; pic ++)
				{
					FILE_read_string_in_file (buffer_0, file_ptr);
					if (strlen (buffer_0) > 0)
					{
						pic_array [pic] = RSC_skin_ptr->merge_pic (buffer_0, false);
						if (pic_array [pic] < 0)
						{
							fclose (file_ptr);
							return (-1);
						}
					}
					else
					{

						pic_array [pic] = -1;
						assert (pic != 0);		// Pas d'image pour l'etat normal
					}
				}
				((RSC_OBJTYPE_BITMAP *) object_ptr)->img [0] = RSC_skin_ptr->add_elt (pic_array);
				break;

			case	RSC_OBJECT_NUMBER_TBITMAP:
				for (pic = 0; pic < 3; pic ++)
				{
					FILE_read_string_in_file (buffer_0, file_ptr);
					if (strlen (buffer_0) > 0)
					{
						pic_array [pic] = RSC_skin_ptr->merge_pic (buffer_0, false);
						if (pic_array [pic] < 0)
						{
							fclose (file_ptr);
							return (-1);
						}
					}
					else
					{
						pic_array [pic] = -1;
						assert (pic != 0);		// Pas d'image pour l'etat normal
					}
				}
				((RSC_OBJTYPE_TBITMAP *) object_ptr)->img [0] = RSC_skin_ptr->add_elt (pic_array);
				break;

			case	RSC_OBJECT_NUMBER_TEXT:
				fscanf (file_ptr, "%d\n",
						  &((RSC_OBJTYPE_TEXT *) object_ptr)->c);
				FILE_read_string_in_file (buffer_0, file_ptr);
				((RSC_OBJTYPE_TEXT *) object_ptr)->text_0 = (char *) STRDUP (buffer_0);
				break;

			case	RSC_OBJECT_NUMBER_TTEXT:
				fscanf (file_ptr, "%d\n",
						  &((RSC_OBJTYPE_TTEXT *) object_ptr)->c);
				FILE_read_string_in_file (buffer_0, file_ptr);
				((RSC_OBJTYPE_TTEXT *) object_ptr)->text_0 = (char *) STRDUP (buffer_0);
				break;

			case	RSC_OBJECT_NUMBER_INTBOX:
				fscanf (file_ptr, "%d %d %d\n",
						  &((RSC_OBJTYPE_INTBOX *) object_ptr)->l,
						  &((RSC_OBJTYPE_INTBOX *) object_ptr)->h,
						  &((RSC_OBJTYPE_INTBOX *) object_ptr)->t);
				break;

			case	RSC_OBJECT_NUMBER_EXTBOX:
				fscanf (file_ptr, "%d %d %d\n",
						  &((RSC_OBJTYPE_EXTBOX *) object_ptr)->l,
						  &((RSC_OBJTYPE_EXTBOX *) object_ptr)->h,
						  &((RSC_OBJTYPE_EXTBOX *) object_ptr)->t);
				break;

			case	RSC_OBJECT_NUMBER_BOXTEXT:
				fscanf (file_ptr, "%d %d %d %d\n",
						  &((RSC_OBJTYPE_BOXTEXT *) object_ptr)->l,
						  &((RSC_OBJTYPE_BOXTEXT *) object_ptr)->h,
						  &((RSC_OBJTYPE_BOXTEXT *) object_ptr)->t,
						  &((RSC_OBJTYPE_BOXTEXT *) object_ptr)->j);
				FILE_read_string_in_file (buffer_0, file_ptr);
				((RSC_OBJTYPE_BOXTEXT *) object_ptr)->text_0 = (char *) STRDUP (buffer_0);
				break;

			case	RSC_OBJECT_NUMBER_EDBOXTEXT:
				fscanf (file_ptr, "%d %d\n",
						  &((RSC_OBJTYPE_EDBOXTEXT *) object_ptr)->l,
						  &((RSC_OBJTYPE_EDBOXTEXT *) object_ptr)->t);
				FILE_read_string_in_file (buffer_0, file_ptr);
				((RSC_OBJTYPE_EDBOXTEXT *) object_ptr)->text_0 = (char *) STRDUP (buffer_0);
				break;

			case	RSC_OBJECT_NUMBER_BUTTON:
				fscanf (file_ptr, "%d %d\n",
						  &((RSC_OBJTYPE_BUTTON *) object_ptr)->t,
						  &((RSC_OBJTYPE_BUTTON *) object_ptr)->t2);

				for (pic = 0; pic < 3; pic ++)
				{
					FILE_read_string_in_file (buffer_0, file_ptr);
					if (strlen (buffer_0) > 0)
					{
						pic_array [pic] = RSC_skin_ptr->merge_pic (buffer_0, false);
						if (pic_array [pic] < 0)
						{
							fclose (file_ptr);
							return (-1);
						}
					}
					else
					{
						pic_array [pic] = -1;
						// Pas d'image pour l'etat normal
						assert ((   pic != 0
						         || ((RSC_OBJTYPE_BUTTON *) object_ptr)->t == RSC_BUTTON_T_UARROW
						         || ((RSC_OBJTYPE_BUTTON *) object_ptr)->t == RSC_BUTTON_T_DARROW
						         || ((RSC_OBJTYPE_BUTTON *) object_ptr)->t == RSC_BUTTON_T_LARROW
						         || ((RSC_OBJTYPE_BUTTON *) object_ptr)->t == RSC_BUTTON_T_RARROW));
					}
				}
				((RSC_OBJTYPE_BUTTON *) object_ptr)->img [0] = RSC_skin_ptr->add_elt (pic_array);
				break;

			default:
				break;
			}
		}

		/* Fin du fichier */
		else if (strcmp (buffer_0, "END_OF_FILE") == 0)
		{
			break;
		}

		if (ferror (file_ptr))
		{
			LOG_printf ("RSC_load_resource_file: Error: read error.\n");
			fclose (file_ptr);
			return (-1);
			break;
		}
	}

	/* Fermeture */
	fclose (file_ptr);
	LOG_printf ("\tOK.\n");

	return (0);
}



/*==========================================================================*/
/*      Nom: RSC_set_skin                                                   */
/*      Description: Change de skin.                                        */
/*      Parametres en entree:                                               */
/*        - path_0: Pointeur sur la chaine contenant le chemin absolu (et   */
/*                  sans nom de fichier) de la skin.                        */
/*      Retour: 0 si tout s'est bien passe.                                 */
/*==========================================================================*/

signed int	RSC_set_skin (const char *path_0)
{
	if (RSC_skin_ptr->restore_standard_skin ())
	{
		LOG_printf ("RSC_set_skin: Error: couldn't remove old skin.\n");
		return (-1);
	}

	if (RSC_skin_ptr->load_custom_skin (path_0))
	{
		LOG_printf ("RSC_set_skin: Error: couldn't load new skin..\n");
		return (-1);
	}

	if (INTR_graph_ptr->set_font (RSC_CHAR_W, RSC_CHAR_H,
	                              RSC_skin_ptr->get_pic_ptr (RSC_gfx_nbr [RSC_GFX_FONT])->get_data_ptr ()))
	{
		LOG_printf ("RSC_set_skin: Error: couldn't set font.\n");
		return (-1);
	}

	return (0);
}



/*==========================================================================*/
/*      Nom:                                                                */
/*      Description:                                                        */
/*      Parametres en entree:                                               */
/*      Parametres en sortie:                                               */
/*      Parametres en entree/sortie:                                        */
/*      Retour:                                                             */
/*==========================================================================*/

Image	*RSC_pcxload (const char *name_0, LWORD pal_ptr [256])
{
	int		tavu1;
	int		tavu2;
	int		i;
	long		p;
	long		w;
	long		h;
	long		pic_size;
	Image		*image_ptr;
	UBYTE		*pic_ptr;
	UBYTE		*pic_2_ptr;
	UBYTE		color [3];
	FILE		*pcx_ptr;
	
	pcx_ptr = FILE_fopen (name_0, "rb");
	if (pcx_ptr == NULL)
	{
		LOG_printf ("RSC_pcxload: Error: couldn't find %s file.\n", name_0);
		return (NULL);
	}
	FILE_fseek (pcx_ptr, 8, SEEK_SET);

	w = fgetc (pcx_ptr);
	w += (fgetc (pcx_ptr) << 8) + 1;
	h = fgetc (pcx_ptr);
	h += (fgetc (pcx_ptr) << 8) + 1;

	image_ptr = new Image (w, h);
	if (image_ptr == NULL)
	{
		LOG_printf ("RSC_pcxload: Error: couldn't create picture.\n");
		fclose (pcx_ptr);
		return (NULL);
	}

	if (w & 1)
	{
		pic_ptr = (UBYTE *) MALLOC ((w + 1) * h);
		if (pic_ptr == NULL)
		{
			LOG_printf ("RSC_pcxload: Error: couldn't allocate temporary space for picture loading.\n");
			fclose (pcx_ptr);
			return (NULL);
		}
		pic_size = (w + 1) * h - 1;
	}
	else
	{
		pic_ptr = image_ptr->get_data_ptr ();
		pic_size = w * h;
	}

	/* Load image */
	FILE_fseek (pcx_ptr, 128, SEEK_SET);
	for (p = 0; p < pic_size; )
	{
		tavu1 = fgetc (pcx_ptr);
		if (tavu1 > 192)
		{
			tavu2 = fgetc (pcx_ptr);
			for ( ; tavu1 > 192 && p < pic_size; tavu1 --)
			{
				pic_ptr [p] = tavu2;
				p ++;
			}
		}
      else
		{
			pic_ptr [p] = tavu1;
			p ++;
		}
	}

	if (w & 1)
	{
		MCHECK (pic_ptr);
		pic_2_ptr = image_ptr->get_data_ptr ();
		for (h -- ; h >= 0; h --)
		{
			memcpy (pic_2_ptr + h * w, pic_ptr + h * (w + 1), w);
		}
		FREE (pic_ptr);
	}

	/* Load palette */
	if (pal_ptr != NULL)
	{
		FILE_fseek (pcx_ptr, -768, SEEK_END);
		for (i = 0; i < 256; i ++)
		{
			fread (color, 1, 3, pcx_ptr);
			pal_ptr [i] =   ((LWORD)color [0] << 16)
			              + ((LWORD)color [1] << 8)
			              + color [2];
		}
	}

	fclose (pcx_ptr);

	return (image_ptr);
}



/*==========================================================================*/
/*      Nom: RSC_get_object_len                                             */
/*      Description: Renvoie la taille d'un objet.                          */
/*      Parametres en entree:                                               */
/*        - object_type: type de l'objet dont on veut connaitre la taille.  */
/*      Retour: Taille de l'objet, en octets.                               */
/*==========================================================================*/

long	RSC_get_object_len (int object_type)
{
	long		object_len;

	switch (object_type)
	{
	case	RSC_OBJECT_NUMBER_NULL:
		object_len = sizeof (RSC_OBJTYPE_NULL);
		break;
	case	RSC_OBJECT_NUMBER_POINT:
		object_len = sizeof (RSC_OBJTYPE_POINT);
		break;
	case	RSC_OBJECT_NUMBER_HLINE:
		object_len = sizeof (RSC_OBJTYPE_HLINE);
		break;
	case	RSC_OBJECT_NUMBER_VLINE:
		object_len = sizeof (RSC_OBJTYPE_VLINE);
		break;
	case	RSC_OBJECT_NUMBER_BOX:
		object_len = sizeof (RSC_OBJTYPE_BOX);
		break;
	case	RSC_OBJECT_NUMBER_XORBOX:
		object_len = sizeof (RSC_OBJTYPE_XORBOX);
		break;
	case	RSC_OBJECT_NUMBER_BITMAP:
		object_len = sizeof (RSC_OBJTYPE_BITMAP);
		break;
	case	RSC_OBJECT_NUMBER_TBITMAP:
		object_len = sizeof (RSC_OBJTYPE_TBITMAP);
		break;
	case	RSC_OBJECT_NUMBER_TEXT:
		object_len = sizeof (RSC_OBJTYPE_TEXT);
		break;
	case	RSC_OBJECT_NUMBER_TTEXT:
		object_len = sizeof (RSC_OBJTYPE_TTEXT);
		break;
	case	RSC_OBJECT_NUMBER_INTBOX:
		object_len = sizeof (RSC_OBJTYPE_INTBOX);
		break;
	case	RSC_OBJECT_NUMBER_EXTBOX:
		object_len = sizeof (RSC_OBJTYPE_EXTBOX);
		break;
	case	RSC_OBJECT_NUMBER_BOXTEXT:
		object_len = sizeof (RSC_OBJTYPE_BOXTEXT);
		break;
	case	RSC_OBJECT_NUMBER_EDBOXTEXT:
		object_len = sizeof (RSC_OBJTYPE_EDBOXTEXT);
		break;
	case	RSC_OBJECT_NUMBER_BUTTON:
		object_len = sizeof (RSC_OBJTYPE_BUTTON);
		break;
	default:
		object_len = 0;
		break;
	}

	return (object_len);
}



/*==========================================================================*/
/*      Nom:                                                                */
/*      Description:                                                        */
/*      Parametres en entree:                                               */
/*      Parametres en sortie:                                               */
/*      Parametres en entree/sortie:                                        */
/*      Retour:                                                             */
/*==========================================================================*/

int	RSC_duplicate_object (int object, bool brother_flag)
{
	int		new_object;
	long		obj_len;
	RSC_OBJTYPE_HEADER	*object_ptr;
	RSC_OBJTYPE_HEADER	*new_object_ptr;

	if (object < 0)
	{
		return (-1);
	}

	object_ptr = RSC_object_ptr [object];
	obj_len = RSC_get_object_len (object_ptr->primitive);
	new_object_ptr = (RSC_OBJTYPE_HEADER *) MALLOC (obj_len);
	memcpy (new_object_ptr, object_ptr, obj_len);
	new_object = 0;
	while (RSC_object_ptr [new_object] != NULL)
	{
		new_object ++;
	}
	RSC_object_ptr [new_object] = new_object_ptr;
	RSC_absolute_object_pixxpos [new_object] = RSC_absolute_object_pixxpos [object];
	RSC_absolute_object_pixypos [new_object] = RSC_absolute_object_pixypos [object];

	switch (object_ptr->primitive)
	{
	case	RSC_OBJECT_NUMBER_BOXTEXT:
		((RSC_OBJTYPE_BOXTEXT *)new_object_ptr)->text_0 =
			STRDUP (((RSC_OBJTYPE_BOXTEXT *)object_ptr)->text_0);
		break;
	case	RSC_OBJECT_NUMBER_TEXT:
		((RSC_OBJTYPE_TEXT *)new_object_ptr)->text_0 =
			STRDUP (((RSC_OBJTYPE_TEXT *)object_ptr)->text_0);
		break;
	case	RSC_OBJECT_NUMBER_TTEXT:
		((RSC_OBJTYPE_TTEXT *)new_object_ptr)->text_0 =
			STRDUP (((RSC_OBJTYPE_TTEXT *)object_ptr)->text_0);
		break;
	case	RSC_OBJECT_NUMBER_EDBOXTEXT:
		((RSC_OBJTYPE_EDBOXTEXT *)new_object_ptr)->text_0 =
			STRDUP (((RSC_OBJTYPE_EDBOXTEXT *)object_ptr)->text_0);
		break;
	}

	if (brother_flag)
	{
		new_object_ptr->brother.number = RSC_duplicate_object (object_ptr->brother.number, true);
	}
	else
	{
		new_object_ptr->brother.number = -1;
	}
	new_object_ptr->child.number = RSC_duplicate_object (object_ptr->child.number, true);

	return (new_object);
}



/*==========================================================================*/
/*      Nom:                                                                */
/*      Description:                                                        */
/*      Parametres en entree:                                               */
/*      Parametres en sortie:                                               */
/*      Parametres en entree/sortie:                                        */
/*      Retour:                                                             */
/*==========================================================================*/

void	RSC_delete_object (int object, bool brother_flag)
{
	RSC_OBJTYPE_HEADER	*object_ptr;

	if (object < 0)
	{
		return;
	}

	object_ptr = RSC_object_ptr [object];

	RSC_delete_object (object_ptr->child.number, true);
	if (brother_flag)
	{
		RSC_delete_object (object_ptr->brother.number, true);
	}

	switch (object_ptr->primitive)
	{
	case	RSC_OBJECT_NUMBER_BOXTEXT:
		FREE (((RSC_OBJTYPE_BOXTEXT *)object_ptr)->text_0);
		break;
	case	RSC_OBJECT_NUMBER_TEXT:
		FREE (((RSC_OBJTYPE_TEXT *)object_ptr)->text_0);
		break;
	case	RSC_OBJECT_NUMBER_TTEXT:
		FREE (((RSC_OBJTYPE_TTEXT *)object_ptr)->text_0);
		break;
	case	RSC_OBJECT_NUMBER_EDBOXTEXT:
		FREE (((RSC_OBJTYPE_EDBOXTEXT *)object_ptr)->text_0);
		break;
	}

	FREE (object_ptr);
	RSC_object_ptr [object] = NULL;
}



/*==========================================================================*/
/*      Nom:                                                                */
/*      Description:                                                        */
/*      Parametres en entree:                                               */
/*      Parametres en sortie:                                               */
/*      Parametres en entree/sortie:                                        */
/*      Retour:                                                             */
/*==========================================================================*/

int	RSC_get_brother (int object)
{
	return (RSC_object_ptr [object]->brother.number);
}



/*==========================================================================*/
/*      Nom:                                                                */
/*      Description:                                                        */
/*      Parametres en entree:                                               */
/*      Parametres en sortie:                                               */
/*      Parametres en entree/sortie:                                        */
/*      Retour:                                                             */
/*==========================================================================*/

int	RSC_get_child (int object)
{
	return (RSC_object_ptr [object]->child.number);
}



/*==========================================================================*/
/*      Nom: RSC_get_width                                                  */
/*      Description: Renvoie la largeur de l'objet si elle existe.          */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet concerne.                             */
/*      Retour: Largeur de l'objet, 0 si l'objet n'a pas de largeur.        */
/*==========================================================================*/

int	RSC_get_width (int object)
{
	int	l;
	RSC_OBJTYPE_HEADER	*object_ptr;
	Image		*pic_ptr;
	bool		bidon_flag;
	bool		bidon_flag_2;

	l = 0;
	object_ptr = RSC_object_ptr [object];
	switch (object_ptr->primitive)
	{
	case	RSC_OBJECT_NUMBER_POINT:
		l = 1;
		break;
	case	RSC_OBJECT_NUMBER_HLINE:
		l = ((RSC_OBJTYPE_HLINE *)object_ptr)->l;
		break;
	case	RSC_OBJECT_NUMBER_VLINE:
		l = 1;
		break;
	case	RSC_OBJECT_NUMBER_BOX:
		l = ((RSC_OBJTYPE_BOX *)object_ptr)->l;
		break;
	case	RSC_OBJECT_NUMBER_XORBOX:
		l = ((RSC_OBJTYPE_XORBOX *)object_ptr)->l;
		break;
	case	RSC_OBJECT_NUMBER_BITMAP:
		pic_ptr = RSC_get_button_picture_ptr (object_ptr, ((RSC_OBJTYPE_BITMAP *)object_ptr)->img [0], bidon_flag, bidon_flag_2);
		l = pic_ptr->get_width ();
		break;
	case	RSC_OBJECT_NUMBER_TBITMAP:
		pic_ptr = RSC_get_button_picture_ptr (object_ptr, ((RSC_OBJTYPE_TBITMAP *)object_ptr)->img [0], bidon_flag, bidon_flag_2);
		l = pic_ptr->get_width ();
		break;
	case	RSC_OBJECT_NUMBER_INTBOX:
		l = ((RSC_OBJTYPE_INTBOX *)object_ptr)->l;
		break;
	case	RSC_OBJECT_NUMBER_EXTBOX:
		l = ((RSC_OBJTYPE_EXTBOX *)object_ptr)->l;
		break;
	case	RSC_OBJECT_NUMBER_BOXTEXT:
		l = ((RSC_OBJTYPE_BOXTEXT *)object_ptr)->l;
		break;
	case	RSC_OBJECT_NUMBER_TEXT:
		l = int (strlen (((RSC_OBJTYPE_TEXT *)object_ptr)->text_0)) * RSC_CHAR_W;
		break;
	case	RSC_OBJECT_NUMBER_TTEXT:
		l = int (strlen (((RSC_OBJTYPE_TTEXT *)object_ptr)->text_0)) * RSC_CHAR_W;
		break;
	case	RSC_OBJECT_NUMBER_EDBOXTEXT:
		l = ((RSC_OBJTYPE_EDBOXTEXT *)object_ptr)->l;
		break;
	case	RSC_OBJECT_NUMBER_BUTTON:
		switch (((RSC_OBJTYPE_BUTTON *)object_ptr)->t)
		{
		case	RSC_BUTTON_T_UARROW:
		case	RSC_BUTTON_T_DARROW:
		case	RSC_BUTTON_T_LARROW:
		case	RSC_BUTTON_T_RARROW:
			l = RSC_CHAR_W * 2;
			break;
		default:
			pic_ptr = RSC_get_button_picture_ptr (object_ptr, ((RSC_OBJTYPE_BUTTON *)object_ptr)->img [0], bidon_flag, bidon_flag_2);
			l = pic_ptr->get_width ();
			break;
		}
		break;
	}

	return (l);
}



/*==========================================================================*/
/*      Nom: RSC_set_width                                                  */
/*      Description: Fixe la largeur de l'objet si c'est possible. Les      */
/*                   longueur des chaines de caractere ne sont pas          */
/*                   modifiees.                                             */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet concerne.                             */
/*        - l: largeur de l'objet.                                          */
/*==========================================================================*/

void	RSC_set_width (int object, int l)
{
	RSC_OBJTYPE_HEADER	*object_ptr;

	object_ptr = RSC_object_ptr [object];
	switch (object_ptr->primitive)
	{
	case	RSC_OBJECT_NUMBER_HLINE:
		((RSC_OBJTYPE_HLINE *)object_ptr)->l = l;
		break;
	case	RSC_OBJECT_NUMBER_BOX:
		((RSC_OBJTYPE_BOX *)object_ptr)->l = l;
		break;
	case	RSC_OBJECT_NUMBER_XORBOX:
		((RSC_OBJTYPE_XORBOX *)object_ptr)->l = l;
		break;
	case	RSC_OBJECT_NUMBER_INTBOX:
		((RSC_OBJTYPE_INTBOX *)object_ptr)->l = l;
		break;
	case	RSC_OBJECT_NUMBER_EXTBOX:
		((RSC_OBJTYPE_EXTBOX *)object_ptr)->l = l;
		break;
	case	RSC_OBJECT_NUMBER_BOXTEXT:
		((RSC_OBJTYPE_BOXTEXT *)object_ptr)->l = l;
		break;
	case	RSC_OBJECT_NUMBER_EDBOXTEXT:
		((RSC_OBJTYPE_EDBOXTEXT *)object_ptr)->l = l;
		break;
	}
}



/*==========================================================================*/
/*      Nom: RSC_get_height                                                 */
/*      Description: Renvoie la hauteur de l'objet si elle existe.          */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet concerne.                             */
/*      Retour: Hauteur de l'objet, 0 si l'objet n'a pas de hauteur.        */
/*==========================================================================*/

int	RSC_get_height (int object)
{
	int	h;
	RSC_OBJTYPE_HEADER	*object_ptr;
	Image		*pic_ptr;
	bool		bidon_flag;
	bool		bidon_flag_2;

	h = 0;
	object_ptr = RSC_object_ptr [object];
	switch (object_ptr->primitive)
	{
	case	RSC_OBJECT_NUMBER_NULL:
		break;
	case	RSC_OBJECT_NUMBER_POINT:
		h = 1;
		break;
	case	RSC_OBJECT_NUMBER_HLINE:
		h = 1;
		break;
	case	RSC_OBJECT_NUMBER_VLINE:
		h = ((RSC_OBJTYPE_VLINE *)object_ptr)->h;
		break;
	case	RSC_OBJECT_NUMBER_BOX:
		h = ((RSC_OBJTYPE_BOX *)object_ptr)->h;
		break;
	case	RSC_OBJECT_NUMBER_XORBOX:
		h = ((RSC_OBJTYPE_XORBOX *)object_ptr)->h;
		break;
	case	RSC_OBJECT_NUMBER_BITMAP:
		pic_ptr = RSC_get_button_picture_ptr (object_ptr, ((RSC_OBJTYPE_BITMAP *)object_ptr)->img [0], bidon_flag, bidon_flag_2);
		h = pic_ptr->get_height ();
		break;
	case	RSC_OBJECT_NUMBER_TBITMAP:
		pic_ptr = RSC_get_button_picture_ptr (object_ptr, ((RSC_OBJTYPE_TBITMAP *)object_ptr)->img [0], bidon_flag, bidon_flag_2);
		h = pic_ptr->get_height ();
		break;
	case	RSC_OBJECT_NUMBER_INTBOX:
		h = ((RSC_OBJTYPE_INTBOX *)object_ptr)->h;
		break;
	case	RSC_OBJECT_NUMBER_EXTBOX:
		h = ((RSC_OBJTYPE_EXTBOX *)object_ptr)->h;
		break;
	case	RSC_OBJECT_NUMBER_BOXTEXT:
		h = ((RSC_OBJTYPE_BOXTEXT *)object_ptr)->h;
		break;
	case	RSC_OBJECT_NUMBER_TEXT:
		h = RSC_CHAR_H;
		break;
	case	RSC_OBJECT_NUMBER_TTEXT:
		h = RSC_CHAR_H;
		break;
	case	RSC_OBJECT_NUMBER_EDBOXTEXT:
		h = RSC_CHAR_H;
		break;
	case	RSC_OBJECT_NUMBER_BUTTON:
		switch (((RSC_OBJTYPE_BUTTON *)object_ptr)->t)
		{
		case	RSC_BUTTON_T_UARROW:
		case	RSC_BUTTON_T_DARROW:
		case	RSC_BUTTON_T_LARROW:
		case	RSC_BUTTON_T_RARROW:
			h = RSC_BOXTEXT_H;
			break;
		default:
			pic_ptr = RSC_get_button_picture_ptr (object_ptr, ((RSC_OBJTYPE_BUTTON *)object_ptr)->img [0], bidon_flag, bidon_flag_2);
			h = pic_ptr->get_height ();
			break;
		}
		break;
	}

	return (h);
}



/*==========================================================================*/
/*      Nom: RSC_set_height                                                 */
/*      Description: Fixe la hauteur de l'objet si c'est possible.          */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet concerne.                             */
/*        - h: hauteur de l'objet.                                          */
/*==========================================================================*/

void	RSC_set_height (int object, int h)
{
	RSC_OBJTYPE_HEADER	*object_ptr;

	object_ptr = RSC_object_ptr [object];
	switch (object_ptr->primitive)
	{
	case	RSC_OBJECT_NUMBER_VLINE:
		((RSC_OBJTYPE_VLINE *)object_ptr)->h = h;
		break;
	case	RSC_OBJECT_NUMBER_BOX:
		((RSC_OBJTYPE_BOX *)object_ptr)->h = h;
		break;
	case	RSC_OBJECT_NUMBER_XORBOX:
		((RSC_OBJTYPE_XORBOX *)object_ptr)->h = h;
		break;
	case	RSC_OBJECT_NUMBER_INTBOX:
		((RSC_OBJTYPE_INTBOX *)object_ptr)->h = h;
		break;
	case	RSC_OBJECT_NUMBER_EXTBOX:
		((RSC_OBJTYPE_EXTBOX *)object_ptr)->h = h;
		break;
	case	RSC_OBJECT_NUMBER_BOXTEXT:
		((RSC_OBJTYPE_BOXTEXT *)object_ptr)->h = h;
		break;
	}
}



/*==========================================================================*/
/*      Nom: RSC_get_color                                                  */
/*      Description: Renvoie la couleur de l'objet si c'est possible.       */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet concerne.                             */
/*      Retour: couleur de l'objet, 0 si la couleur de l'objet ne peut pas  */
/*              etre obtenue.                                               */
/*==========================================================================*/

int	RSC_get_color (int object)
{
	int		c;
	RSC_OBJTYPE_HEADER	*object_ptr;

	object_ptr = RSC_object_ptr [object];
	switch (object_ptr->primitive)
	{
	case	RSC_OBJECT_NUMBER_POINT:
		c = ((RSC_OBJTYPE_POINT *)object_ptr)->c;
		break;
	case	RSC_OBJECT_NUMBER_HLINE:
		c = ((RSC_OBJTYPE_HLINE *)object_ptr)->c;
		break;
	case	RSC_OBJECT_NUMBER_VLINE:
		c = ((RSC_OBJTYPE_VLINE *)object_ptr)->c;
		break;
	case	RSC_OBJECT_NUMBER_BOX:
		c = ((RSC_OBJTYPE_BOX *)object_ptr)->c;
		break;
	case	RSC_OBJECT_NUMBER_XORBOX:
		c = ((RSC_OBJTYPE_XORBOX *)object_ptr)->c;
		break;
	case	RSC_OBJECT_NUMBER_TEXT:
		c = ((RSC_OBJTYPE_TEXT *)object_ptr)->c;
		break;
	case	RSC_OBJECT_NUMBER_TTEXT:
		c = ((RSC_OBJTYPE_TTEXT *)object_ptr)->c;
		break;
	default:
		c = 0;
	}

	return (c);
}



/*==========================================================================*/
/*      Nom: RSC_set_color                                                  */
/*      Description: Fixe la couleur de l'objet si c'est possible.          */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet concerne.                             */
/*        - c: couleur de l'objet.                                          */
/*==========================================================================*/

void	RSC_set_color (int object, int c)
{
	RSC_OBJTYPE_HEADER	*object_ptr;

	object_ptr = RSC_object_ptr [object];
	switch (object_ptr->primitive)
	{
	case	RSC_OBJECT_NUMBER_POINT:
		((RSC_OBJTYPE_POINT *)object_ptr)->c = c;
		break;
	case	RSC_OBJECT_NUMBER_HLINE:
		((RSC_OBJTYPE_HLINE *)object_ptr)->c = c;
		break;
	case	RSC_OBJECT_NUMBER_VLINE:
		((RSC_OBJTYPE_VLINE *)object_ptr)->c = c;
		break;
	case	RSC_OBJECT_NUMBER_BOX:
		((RSC_OBJTYPE_BOX *)object_ptr)->c = c;
		break;
	case	RSC_OBJECT_NUMBER_XORBOX:
		((RSC_OBJTYPE_XORBOX *)object_ptr)->c = c;
		break;
	case	RSC_OBJECT_NUMBER_TEXT:
		((RSC_OBJTYPE_TEXT *)object_ptr)->c = c;
		break;
	case	RSC_OBJECT_NUMBER_TTEXT:
		((RSC_OBJTYPE_TTEXT *)object_ptr)->c = c;
		break;
	}
}



/*==========================================================================*/
/*      Nom: RSC_get_string                                                 */
/*      Description: Renvoie un pointeur sur la chaine associee a l'objet,  */
/*                   si elle existe.                                        */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet concerne.                             */
/*      Retour: Pointeur sur la chaine, NULL si la chaine n'existait pas.   */
/*==========================================================================*/

char	*RSC_get_string (int object)
{
	RSC_OBJTYPE_HEADER	*object_ptr;
	char		*string_0;

	object_ptr = RSC_object_ptr [object];
	switch (object_ptr->primitive)
	{
	case	RSC_OBJECT_NUMBER_TEXT:
		string_0 = ((RSC_OBJTYPE_TEXT *) object_ptr)->text_0;
		break;
	case	RSC_OBJECT_NUMBER_TTEXT:
		string_0 = ((RSC_OBJTYPE_TTEXT *) object_ptr)->text_0;
		break;
	case	RSC_OBJECT_NUMBER_BOXTEXT:
		string_0 = ((RSC_OBJTYPE_BOXTEXT *) object_ptr)->text_0;
		break;
	case	RSC_OBJECT_NUMBER_EDBOXTEXT:
		string_0 = ((RSC_OBJTYPE_EDBOXTEXT *) object_ptr)->text_0;
		break;
	default:
		string_0 = 0;
		break;
	}

	return (string_0);
}



/*==========================================================================*/
/*      Nom: RSC_set_string                                                 */
/*      Description: Recopie une chaine quelconque dans la chaine d'un      */
/*                   objet. La chaine est tronquee si elle est trop longue  */
/*                   ou complete a droite par des espaces si elle est trop  */
/*                   courte.                                                */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet dans lequel on veut copier la chaine. */
/*        - text_0: pointeur sur la chaine a copier, NULL si on ne veut que */
/*                  des espaces.                                            */
/*      Retour: 0 si tout s'est bien passe, -1 si l'objet n'a pas de chaine */
/*              dans ses donnees.                                           */
/*==========================================================================*/

signed int	RSC_set_string (int object, const char *text_0)
{
	RSC_OBJTYPE_HEADER	*object_ptr;

	object_ptr = RSC_object_ptr [object];
	switch (object_ptr->primitive)
	{
	case	RSC_OBJECT_NUMBER_TEXT:
		FREE (((RSC_OBJTYPE_TEXT *) object_ptr)->text_0);
		((RSC_OBJTYPE_TEXT *) object_ptr)->text_0 = STRDUP (text_0);
		break;
	case	RSC_OBJECT_NUMBER_TTEXT:
		FREE (((RSC_OBJTYPE_TTEXT *) object_ptr)->text_0);
		((RSC_OBJTYPE_TTEXT *) object_ptr)->text_0 = STRDUP (text_0);
		break;
	case	RSC_OBJECT_NUMBER_BOXTEXT:
		FREE (((RSC_OBJTYPE_BOXTEXT *) object_ptr)->text_0);
		((RSC_OBJTYPE_BOXTEXT *) object_ptr)->text_0 = STRDUP (text_0);
		break;
	case	RSC_OBJECT_NUMBER_EDBOXTEXT:
		FREE (((RSC_OBJTYPE_EDBOXTEXT *) object_ptr)->text_0);
		((RSC_OBJTYPE_EDBOXTEXT *) object_ptr)->text_0 = STRDUP (text_0);
		break;
	default:
		LOG_printf ("RSC_set_string: Error: object %d doesn't contain any string.\n",
		            object);
		return (-1);
		break;
	}

	return (0);
}



/*==========================================================================*/
/*      Nom: RSC_select_object_display                                      */
/*      Description: Selectionne ou deselectionne un objet, puis l'affiche. */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet concerne.                             */
/*        - flag: indicateur de selection de l'objet.                       */
/*==========================================================================*/

void	RSC_select_object_display (int object, bool flag)
{
	RSC_pos_flag (object, RSC_ATTR_SELECTED, flag);
	RSC_display_object (object);
}



/*==========================================================================*/
/*      Nom: RSC_select_radio_button													 */
/*      Description: Selectionne un Radio-button d'une liste de Radio-      */
/*                   buttons. Les autres radio-buttons sont desactives.     */
/*                   Aucun affichage n'est fait.                            */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet a activer                             */
/*        - aine: aine des radio-buttons de la liste.                       */
/*==========================================================================*/

void	RSC_select_radio_button (int object, int aine)
{
	do
	{
		if ((RSC_object_ptr [aine]->attributes & RSC_ATTR_RADIO) != 0)
		{
			RSC_pos_flag (aine, RSC_ATTR_SELECTED, aine == object);
		}
		aine = RSC_object_ptr [aine]->brother.number;
	}
	while (aine >= 0);
}



/*==========================================================================*/
/*      Nom: RSC_select_radio_button_display                                */
/*      Description: Selectionne un Radio-button d'une liste de Radio-      */
/*                   buttons. Les autres radio-buttons sont desactives.     */
/*                   Affiche tous les radio-boutons du groupe.              */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet a activer                             */
/*        - aine: aine des radio-buttons de la liste.                       */
/*==========================================================================*/

void	RSC_select_radio_button_display (int object, int aine)
{
	do
	{
		if ((RSC_object_ptr [aine]->attributes & RSC_ATTR_RADIO) != 0)
		{
			RSC_select_object_display (aine, aine == object);
		}
		aine = RSC_object_ptr [aine]->brother.number;
	}
	while (aine >= 0);
}



/*==========================================================================*/
/*      Nom: RSC_set_flag                                                   */
/*      Description: Mets a 1 les flags specifies d'un objet.               */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet                                       */
/*        - flag: combinaison de 1 ou plusieurs flags (OU bit a bit).       */
/*==========================================================================*/

void	RSC_set_flag (int object, LWORD flag)
{
	RSC_object_ptr [object]->attributes |= flag;
}



/*==========================================================================*/
/*      Nom: RSC_clear_flag                                                 */
/*      Description: Mets a 0 les flags specifies d'un objet.               */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet                                       */
/*        - flag: combinaison de 1 ou plusieurs flags (OU bit a bit).       */
/*==========================================================================*/

void	RSC_clear_flag (int object, LWORD flag)
{
	RSC_object_ptr [object]->attributes &= ~flag;
}



/*==========================================================================*/
/*      Nom: RSC_pos_flag                                                   */
/*      Description: Mets a 0 ou 1 les flags specifies d'un objet.          */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet                                       */
/*        - flag: combinaison de 1 ou plusieurs flags (OU bit a bit).       */
/*        - state: true si les flags doivent etre mis, false sinon.         */
/*==========================================================================*/

void	RSC_pos_flag (int object, LWORD flag, bool state)
{
	if (state)
	{
		RSC_set_flag (object, flag);
	}
	else
	{
		RSC_clear_flag (object, flag);
	}
}



/*==========================================================================*/
/*      Nom: RSC_test_flag                                                  */
/*      Description: Teste les flags specifies d'un objet.                  */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet                                       */
/*        - flag: combinaison de 1 ou plusieurs flags (OU bit a bit).       */
/*      Retour: true si au moins un des flag demandes est a 1, false sinon. */
/*==========================================================================*/

bool	RSC_test_flag (int object, LWORD flag)
{
	return ((RSC_object_ptr [object]->attributes & flag) != 0);
}



/*==========================================================================*/
/*      Nom: RSC_test_all_flags                                             */
/*      Description: Teste les flags specifies d'un objet.                  */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet                                       */
/*        - flag: combinaison de 1 ou plusieurs flags (OU bit a bit).       */
/*      Retour: true si tous les flag demandes sont a 1, false sinon.       */
/*==========================================================================*/

bool	RSC_test_all_flags (int object, LWORD flag)
{
	return ((RSC_object_ptr [object]->attributes & flag) == flag);
}



/*==========================================================================*/
/*      Nom: RSC_set_absolute_object_position                               */
/*      Description: Change les coordonnees absolues d'un objet sur         */
/*                   l'ecran. Du coup les coordonnees absolues des fils     */
/*                   sont mises a jour. Suppose que les coordonnees         */
/*                   absolues de l'objet ont deja ete initialisees.         */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet concerne.                             */
/*        - pixxpos, pixypos: nouvelles coordonnees de l'objet              */
/*==========================================================================*/

void	RSC_set_absolute_object_position (int object, int pixxpos, int pixypos)
{
	RSC_OBJTYPE_HEADER	*object_ptr;
	signed int	inc_x;
	signed int	inc_y;

	inc_x = pixxpos - RSC_absolute_object_pixxpos [object];
	inc_y = pixypos - RSC_absolute_object_pixypos [object];
	object_ptr = RSC_object_ptr [object];
	object_ptr->x += inc_x;
	object_ptr->y += inc_y;
	pixxpos -= object_ptr->x;
	pixypos -= object_ptr->y;
	RSC_set_absolute_object_position_rec (object, pixxpos, pixypos, false);
}



/*==========================================================================*/
/*      Nom: RSC_set_relative_object_position                               */
/*      Description: Renvoie les coordonnees relatives d'un objet sur       */
/*                   l'ecran.                                               */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet concerne.                             */
/*      Parametres en sortie:                                               */
/*        - pixxpos, pixypos: coordonnees de l'objet.                       */
/*==========================================================================*/

void	RSC_get_relative_object_position (int object, int &rel_pixxpos, int &rel_pixypos)
{
	const RSC_OBJTYPE_HEADER	*object_ptr;

	object_ptr = RSC_object_ptr [object];
	rel_pixxpos = object_ptr->x;
	rel_pixypos = object_ptr->y;
}



/*==========================================================================*/
/*      Nom: RSC_set_relative_object_position                               */
/*      Description: Change les coordonnees relatives d'un objet sur        */
/*                   l'ecran. Du coup les coordonnees absolues des fils     */
/*                   sont mises a jour. Suppose que les coordonnees         */
/*                   absolues de l'objet ont deja ete initialisees.         */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet concerne.                             */
/*        - pixxpos, pixypos: nouvelles coordonnees de l'objet              */
/*==========================================================================*/

void	RSC_set_relative_object_position (int object, int rel_pixxpos, int rel_pixypos)
{
	RSC_OBJTYPE_HEADER	*object_ptr;
	signed int	pixxpos;
	signed int	pixypos;

	object_ptr = RSC_object_ptr [object];
	pixxpos = RSC_absolute_object_pixxpos [object] - object_ptr->x;
	pixypos = RSC_absolute_object_pixypos [object] - object_ptr->y;
	object_ptr->x = rel_pixxpos;
	object_ptr->y = rel_pixypos;
	RSC_set_absolute_object_position_rec (object, pixxpos, pixypos, false);
}



/*==========================================================================*/
/*      Nom: RSC_set_absolute_object_position_rec                           */
/*      Description: Change les coordonnees d'un objet sur l'ecran en       */
/*                   specifiant les coordonnees absolues du pere. Du coup   */
/*                   les coordonnees absolues de toute la famille sont      */
/*                   recalculees. Ne necessite pas que le tableau des       */
/*                   coordonnees absolues soit deja initialise.             */
/*                   Cette routine peut servir a initialiser l'arbre en     */
/*                   fixant les coordonnees du pere de l'objet 0 et en      */
/*                   mettant le brother_flag a true.                        */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet concerne.                             */
/*        - pixxpos, pixypos: nouvelles coordonnees de son pere (toutefois  */
/*                            les coordonnees du pere ne sont pas modifiees)*/
/*        - brother_flag: true indique que les freres cadets de l'objet     */
/*                        doivent aussi etre modifies.                      */
/*==========================================================================*/

void	RSC_set_absolute_object_position_rec (int object, int pixxpos, int pixypos, bool brother_flag)
{
	RSC_OBJTYPE_HEADER	*object_ptr;

	object_ptr = RSC_object_ptr [object];
	RSC_absolute_object_pixxpos [object] = pixxpos + object_ptr->x;
	RSC_absolute_object_pixypos [object] = pixypos + object_ptr->y;

	if (object_ptr->child.number >= 0)
	{
		RSC_set_absolute_object_position_rec (object_ptr->child.number,
														  pixxpos + object_ptr->x,
														  pixypos + object_ptr->y, true);
	}
	if (brother_flag && object_ptr->brother.number >= 0)
	{
		RSC_set_absolute_object_position_rec (object_ptr->brother.number,
														  pixxpos, pixypos, true);
	}
}



/*==========================================================================*/
/*      Nom: RSC_is_child                                                   */
/*      Description: Teste si un objet appartient a un sous-arbre           */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet a tester.                             */
/*        - father: sous-arbre sur lequel va s'effectuer le test.           */
/*      Retour: true si object appartient a father.                         */
/*==========================================================================*/

bool	RSC_is_child (int object, int father)
{
	RSC_OBJTYPE_HEADER	*object_ptr;
	
	if (object == father)
	{
		return (true);
	}

	object_ptr = RSC_object_ptr [father];

	if (object_ptr->child.number >= 0)
	{
		if (RSC_is_child (object, object_ptr->child.number))
		{
			return (true);
		}
		object_ptr = RSC_object_ptr [object_ptr->child.number];

		while (object_ptr->brother.number >= 0)
		{
			if (RSC_is_child (object, object_ptr->brother.number))
			{
				return (true);
			}
			object_ptr = RSC_object_ptr [object_ptr->brother.number];
		}
	}

	return (false);
}



/*==========================================================================*/
/*      Nom: RSC_get_pointed_object_number                                  */
/*      Description: Recherche l'objet sous lequel se trouve la souris. Ne  */
/*                   scanne que les objets n'ayant pas l'attribut NOCLICK.  */
/*      Parametres en entree:                                               */
/*        - mouse_x, mouse_y: coordonnees absolues en pixels de la souris.  */
/*        - father: numero de l'objet pere de tous les objets scannes.      */
/*      Parametres en sortie:                                               */
/*        - aine: pointeur sur l'aine du frere de l'objet clique (sert pour */
/*                les radio-boutons).                                       */
/*      Retour: Numero de l'objet sous la souris; -1 si aucun.              */
/*==========================================================================*/

signed int	RSC_get_pointed_object_number (int mouse_x, int mouse_y, int father, int *aine_ptr)
{
	int		pointed_ptr [1];
	int		pointed_level_ptr [1];

	*pointed_level_ptr = -1;
	*pointed_ptr = -1;
	*aine_ptr = -1;
	RSC_get_pointed_object_number_rec (mouse_x, mouse_y, father, father, 0,
												  pointed_level_ptr, pointed_ptr,
												  aine_ptr, false);
	return (*pointed_ptr);
}



/*
 * Recherche par recurence. On teste si l'objet est clique. S'il ne l'est pas,
 * on continue jusqu'a ce qu'on trouve. S'il l'est, on examine ses fils et
 * uniquement ses fils pour voir si c'est pas un objet plus precis qui a ete
 * clique.
 */
void	RSC_get_pointed_object_number_rec (int mouse_x,
													  int mouse_y,
													  int object,
													  int	aine,
													  int current_level,
													  int *pointed_level_ptr,
													  int *pointed_ptr,
													  int	*pointed_aine_ptr,
													  bool brother_flag)
{
	RSC_OBJTYPE_HEADER	*object_ptr;
	int		x;
	int		y;
	int		l;
	int		h;

	if (current_level <= *pointed_level_ptr)
	{
		return;
	}

	x = RSC_absolute_object_pixxpos [object];
	y = RSC_absolute_object_pixypos [object];
	object_ptr = RSC_object_ptr [object];
	if ((object_ptr->attributes & RSC_ATTR_NOTDISP) == 0)
	{
		if ((object_ptr->attributes & RSC_ATTR_NOCLICK) == 0)
		{
			l = RSC_get_width (object);
			h = RSC_get_height (object);
			if (   mouse_x >= x
				 && mouse_x < x + l
				 && mouse_y >= y
				 && mouse_y < y + h)
			{
				*pointed_ptr = object;
				*pointed_aine_ptr = aine;
				*pointed_level_ptr = current_level;
			}
		}

		if (object_ptr->child.number >= 0)
		{
			RSC_get_pointed_object_number_rec (mouse_x, mouse_y,
														  object_ptr->child.number,
														  object_ptr->child.number,
														  current_level + 1, pointed_level_ptr,
														  pointed_ptr, pointed_aine_ptr, true);
		}
	}

	if (   brother_flag && object_ptr->brother.number >= 0
		 && current_level > *pointed_level_ptr)
	{
		RSC_get_pointed_object_number_rec (mouse_x, mouse_y,
													  object_ptr->brother.number,
													  aine,
													  current_level, pointed_level_ptr,
													  pointed_ptr, pointed_aine_ptr, true);
	}
}



/*==========================================================================*/
/*      Nom: RSC_gere_resource                                              */
/*      Description: Examine une famille d'objet, regarde si on a clique    */
/*                   sur l'un d'entre eux (ou qu'on a relache le bouton de  */
/*                   la souris), met a jour les selections et renvoie le    */
/*                   code de l'objet clique le cas echeant.                 */
/*                   La souris doit etre capturee avant chaque appel a      */
/*                   cette fonction.                                        */
/*      Parametres en entree:                                               */
/*        - father: objet pere de la famille a scanner (father est inclus)  */
/*      Parametres en sortie:                                               */
/*        - sel_object_ptr: objet selectionne, -1 si aucune selection.      */
/*        - sel_aine_ptr: objet aine de l'objet selectionne (-1 si rien).   */
/*==========================================================================*/

void	RSC_gere_resource (int father, int *sel_object_ptr, int *sel_aine_ptr)
{
	int		object;
	int		aine;
	int		radio;
	clock_t	current_time;
	int		delay;

	*sel_object_ptr = -1;
	*sel_aine_ptr = -1;
	object = -1;

	/* Objet memorise */
	if (RSC_mem_object >= 0)
	{
		/* Objet memorise dans l'arbre a tester */
		if (RSC_is_child (RSC_mem_object, father))
		{
			/* Clic et capture */
			if (   RSC_test_flag (RSC_mem_object, RSC_ATTR_CAPTURE)
			    && INTR_mouse.k != 0)
			{
				*sel_object_ptr = RSC_mem_object;
				*sel_aine_ptr = RSC_mem_aine;
				object = RSC_mem_object;
				aine = RSC_mem_aine;
			}
		}

		else
		{
			return;
		}
	}

/*______________________________________________
 *
 * Regarde si un objet est selectionne sur
 * la partie de l'arbre scanne
 *______________________________________________
 */

	if (object < 0)
	{
		object = RSC_get_pointed_object_number (INTR_mouse.x, INTR_mouse.y, father, &aine);

		/* Souris enfoncee */
		if (INTR_mouse.k != 0)
		{
			/* Memorise quel est le bouton qui a ete enfonce */
			RSC_mouse_key = INTR_mouse.k;

			/* Un objet a deja ete memorise */
			if (RSC_mem_object >= 0)
			{
				/* L'objet selectionne est different de celui qui est memorise
				   (ou alors on n'a pas clique sur un objet) */
				if (object != RSC_mem_object)
				{
					/* Si l'objet n'est pas permanent, on le deselectionne */
					if (! RSC_test_flag (RSC_mem_object, RSC_ATTR_PERMANENT))
					{
						/* Deselection */
						if (RSC_test_flag (RSC_mem_object, RSC_ATTR_SELECTED))
						{
							RSC_select_object_display (RSC_mem_object, false);
						}
					}

					/* Vire de la memoire */
					RSC_mem_object = -1;
					RSC_mem_aine = -1;
				}
			}

			/* Un objet a bien ete clique */
			if (object >= 0)
			{
				/* Si ce n'est pas la premiere fois qu'on touche a un Permanent, on
				   invalide l'action. */
				if (   ! RSC_test_flag (object, RSC_ATTR_PERMANENT)
				    || RSC_mem_object < 0
				    || RSC_last_click_time == 0)
				{
					/* Memorisation */
					if (object != RSC_mem_object)
					{
						RSC_click_time_base = clock ();
						RSC_last_click_time = 0;
					}
					RSC_mem_object = object;
					RSC_mem_aine = aine;
						
					/* L'objet est Selectable */
					if (RSC_test_flag (object, RSC_ATTR_SELECTABLE))
					{
						/* L'objet est un Radio-button */
						if (RSC_test_flag (object, RSC_ATTR_RADIO))
						{
							/* Deselectionne tous les freres radio et les affiche */
							radio = aine;
							do
							{
								if (   RSC_test_all_flags (radio, RSC_ATTR_RADIO | RSC_ATTR_SELECTED)
								    && radio != object)
								{
									RSC_select_object_display (radio, false);
								}
								radio = RSC_object_ptr [radio]->brother.number;
							}
							while (radio >= 0);
						}

						/* Selectionne l'objet */
						if (! RSC_test_flag (RSC_mem_object, RSC_ATTR_SELECTED))
						{
							RSC_select_object_display (RSC_mem_object, true);
						}

						/* L'objet est Touchexit */
						if (RSC_test_flag (object, RSC_ATTR_TOUCHEXIT))
						{
							/* On sort cet objet */
							*sel_object_ptr = RSC_mem_object;
							*sel_aine_ptr = RSC_mem_aine;
						}
					}

					/* L'objet n'est pas Selectable */
					else
					{
						/* On sort cet objet */
						*sel_object_ptr = object;
						*sel_aine_ptr = aine;
					}
				}
			}
		}

		/* Souris relachee */
		else
		{
			/* Il existe deja un objet memorise */
			if (RSC_mem_object >= 0)
			{
				/* l'objet est de-clique */
				if (object == RSC_mem_object)
				{
					/* L'objet n'est pas Touchexit
					   ou il est actif egalement au relachement */
					if (   ! RSC_test_flag (RSC_mem_object, RSC_ATTR_TOUCHEXIT)
					    || RSC_test_flag (RSC_mem_object, RSC_ATTR_ONRELEASE))
					{
						/* On sort cet objet */
						*sel_object_ptr = RSC_mem_object;
						*sel_aine_ptr = RSC_mem_aine;
					}
				}

				/* Objet non-permanent */
				if (! RSC_test_flag (RSC_mem_object, RSC_ATTR_PERMANENT))
				{
					/* Deselection */
					if (RSC_test_flag (RSC_mem_object, RSC_ATTR_SELECTED))
					{
						RSC_select_object_display (RSC_mem_object, false);
					}
				}

				/* Vire de la memoire */
				RSC_mem_object = -1;
				RSC_mem_aine = -1;
			}
		}		
	}

/*______________________________________________
 *
 * Test de validite du clic (suivant la
 * temporisation).
 *______________________________________________
 */

	if (*sel_object_ptr >= 0)
	{
		/* On doit respecter une temporisation */
		if (   RSC_test_flag (*sel_object_ptr, RSC_ATTR_TOUCHEXIT)
		    && ! RSC_test_flag (*sel_object_ptr, RSC_ATTR_NOTEMPO))
		{
			current_time = clock ();

			/* Clic droit */
			if (INTR_mouse.k & 0x02)
			{
				delay = 50;
			}

			/* Clic gauche */
			else
			{
				/* Temps ecoule depuis le debut du clic < delay de premier appui */
				if ((int) ((long)(current_time - RSC_click_time_base) * 1000 / CLOCKS_PER_SEC) < 400)
				{
					delay = 400;
				}

				/* Temps ecoule depuis le debut du clic >= delay de premier appui: repetition */
				else
				{
					delay = 150;
				}
			}

			/* Suffisamment de temps s'est ecoule depuis le dernier clic: on valide */
			if (   (int) ((long)(current_time - RSC_last_click_time) * 1000 / CLOCKS_PER_SEC) >= delay
			    || RSC_last_click_time == 0)
			{
				RSC_last_click_time = current_time;
			}

			/* Sinon on invalide (ce sera peut-etre pour la prochaine fois) */
			else
			{
				*sel_object_ptr = -1;
				*sel_aine_ptr = -1;
			}
		}
	}
}



/*==========================================================================*/
/*      Nom: RSC_flush_resource                                             */
/*      Description: Deselectionne l'objet memorise eventuellement par un   */
/*                   appel precedent a RSC_gere_resource. Ceci permet       */
/*                   d'eviter son redraw lors d'un RSC_gere_resource sur un */
/*                   objet n'ayant rien a voir avec le precedent.           */
/*                   Routine a executer lors d'un changement d'ecran ou     */
/*                   avant l'affichage d'une boite de dialogue.             */
/*==========================================================================*/

void	RSC_flush_resource (void)
{
	/* On a deja clique sur un objet */
	if (RSC_mem_object >= 0)
	{
		/* S'il n'est pas Permanent et qu'il etait selectionne,
			il faut le deselectionner */
		if (   ! RSC_test_flag (RSC_mem_object, RSC_ATTR_PERMANENT)
		    && RSC_test_flag (RSC_mem_object, RSC_ATTR_SELECTED))
		{
			RSC_select_object_display (RSC_mem_object, false);
		}
	}

	RSC_mem_object = -1;
	RSC_mem_aine = -1;
}



/*==========================================================================*/
/*      Nom: RSC_get_gfx_ptr                                                */
/*      Description: Renvoie le pointeur sur une image specifique de la     */
/*                   resource.                                              */
/*      Parametres en entree:                                               */
/*        - Un numero de graphique RSC_GFX_???                              */
/*      Retour: Pointeur sur l'image.                                       */
/*==========================================================================*/

Image	*RSC_get_gfx_ptr (int gfx)
{
	return (RSC_skin_ptr->get_pic_ptr (RSC_gfx_nbr [gfx]));
}



/*==========================================================================*/
/*      Nom: RSC_display_object                                             */
/*      Description: Affiche un objet quelconque du fichier resource avec   */
/*                   tous ses fils. Efface la souris avant d'agir.          */
/*                   A la fin de l'affichage, l'ecran est libere.           */
/*      Parametres en entree:                                               */
/*        - object: numero de l'objet en question.                          */
/*        - child_flag: indique qu'on veut aussi afficher les fils          */
/*==========================================================================*/

void	RSC_display_object (int object, bool child_flag)
{
	INTR_graph_ptr->hide_mouse ();
	RSC_display_object_recursive (object, false, child_flag);
	INTR_graph_ptr->unlock_screen ();
}



void	RSC_display_object_recursive (int object, bool brother_flag, bool child_flag)
{
	int		new_x;
	int		new_y;
	RSC_OBJTYPE_HEADER	*object_ptr;

	object_ptr = RSC_object_ptr [object];

	if ((object_ptr->attributes & RSC_ATTR_NOTDISP) == 0)
	{
		new_x = RSC_absolute_object_pixxpos [object];
		new_y = RSC_absolute_object_pixypos [object];

		switch (object_ptr->primitive)
		{
		case	RSC_OBJECT_NUMBER_POINT:
			RSC_display_object_point (new_x, new_y, (RSC_OBJTYPE_POINT *)object_ptr);
			break;
		case	RSC_OBJECT_NUMBER_HLINE:
			RSC_display_object_hline (new_x, new_y, (RSC_OBJTYPE_HLINE *)object_ptr);
			break;
		case	RSC_OBJECT_NUMBER_VLINE:
			RSC_display_object_vline (new_x, new_y, (RSC_OBJTYPE_VLINE *)object_ptr);
			break;
		case	RSC_OBJECT_NUMBER_BOX:
			RSC_display_object_box (new_x, new_y, (RSC_OBJTYPE_BOX *)object_ptr);
			break;
		case	RSC_OBJECT_NUMBER_XORBOX:
			RSC_display_object_xorbox (new_x, new_y, (RSC_OBJTYPE_XORBOX *)object_ptr);
			break;
		case	RSC_OBJECT_NUMBER_BITMAP:
			RSC_display_object_bitmap (new_x, new_y, (RSC_OBJTYPE_BITMAP *)object_ptr);
			break;
		case	RSC_OBJECT_NUMBER_TBITMAP:
			RSC_display_object_tbitmap (new_x, new_y, (RSC_OBJTYPE_TBITMAP *)object_ptr);
			break;
		case	RSC_OBJECT_NUMBER_TEXT:
			RSC_display_object_text (new_x, new_y, (RSC_OBJTYPE_TEXT *)object_ptr);
			break;
		case	RSC_OBJECT_NUMBER_TTEXT:
			RSC_display_object_ttext (new_x, new_y, (RSC_OBJTYPE_TTEXT *)object_ptr);
			break;
		case	RSC_OBJECT_NUMBER_INTBOX:
			RSC_display_object_intbox (new_x, new_y, (RSC_OBJTYPE_INTBOX *)object_ptr);
			break;
		case	RSC_OBJECT_NUMBER_EXTBOX:
			RSC_display_object_extbox (new_x, new_y, (RSC_OBJTYPE_EXTBOX *)object_ptr);
			break;
		case	RSC_OBJECT_NUMBER_BOXTEXT:
			RSC_display_object_boxtext (new_x, new_y, (RSC_OBJTYPE_BOXTEXT *)object_ptr);
			break;
		case	RSC_OBJECT_NUMBER_EDBOXTEXT:
			RSC_display_object_edboxtext (new_x, new_y, (RSC_OBJTYPE_EDBOXTEXT *)object_ptr);
			break;
		case	RSC_OBJECT_NUMBER_BUTTON:
			RSC_display_object_button (new_x, new_y, (RSC_OBJTYPE_BUTTON *)object_ptr);
			break;
		}

		if (child_flag && object_ptr->child.number >= 0)
		{
			RSC_display_object_recursive (object_ptr->child.number, true, true);
		}
	}

	if (brother_flag && object_ptr->brother.number >= 0)
	{
		RSC_display_object_recursive (object_ptr->brother.number, true, child_flag);
	}
}



/*==========================================================================*/
/*      Nom: RSC_display_???                                                */
/*      Description: Affiche l'objet de type specifie, tout seul.           */
/*                   Attention, la souris doit d'abord etre effacee.        */
/*      Parametres en entree:                                               */
/*        - pix_x, pix_y: coordonnees absolues en pixels de l'objet.        */
/*        - object_ptr: pointeur sur la structure de l'objet                */
/*==========================================================================*/

void	RSC_display_object_point (int pix_x, int pix_y, const RSC_OBJTYPE_POINT *object_ptr)
{
	INTR_graph_ptr->display_point (pix_x, pix_y, RSC_skin_ptr->map_color (object_ptr->c));

	if (object_ptr->header.attributes & RSC_ATTR_DISABLE)
	{
		INTR_graph_ptr->disable_zone (pix_x, pix_y, 1, 1, RSC_skin_ptr->map_color (0));
	}
}



void	RSC_display_object_hline (int pix_x, int pix_y, const RSC_OBJTYPE_HLINE *object_ptr)
{
	INTR_graph_ptr->display_hline (pix_x, pix_y, object_ptr->l, RSC_skin_ptr->map_color (object_ptr->c));

	if (object_ptr->header.attributes & RSC_ATTR_DISABLE)
	{
		INTR_graph_ptr->disable_zone (pix_x, pix_y, object_ptr->l, 1, RSC_skin_ptr->map_color (0));
	}
}



void	RSC_display_object_vline (int pix_x, int pix_y, const RSC_OBJTYPE_VLINE *object_ptr)
{
	INTR_graph_ptr->display_vline (pix_x, pix_y, object_ptr->h, RSC_skin_ptr->map_color (object_ptr->c));

	if (object_ptr->header.attributes & RSC_ATTR_DISABLE)
	{
		INTR_graph_ptr->disable_zone (pix_x, pix_y, 1, object_ptr->h, RSC_skin_ptr->map_color (0));
	}
}



void	RSC_display_object_box (int pix_x, int pix_y, const RSC_OBJTYPE_BOX *object_ptr)
{
	Graphic_FRAME_INFO	cadre;

	cadre.x = pix_x;
	cadre.y = pix_y;
	cadre.l = object_ptr->l;
	cadre.h = object_ptr->h;
	cadre.backgc = RSC_skin_ptr->map_color (object_ptr->c);
	INTR_graph_ptr->display_box (&cadre);

	if (object_ptr->header.attributes & RSC_ATTR_DISABLE)
	{
		INTR_graph_ptr->disable_zone (pix_x, pix_y, object_ptr->l, object_ptr->h, RSC_skin_ptr->map_color (0));
	}
}



void	RSC_display_object_xorbox (int pix_x, int pix_y, const RSC_OBJTYPE_XORBOX *object_ptr)
{
	Graphic_FRAME_INFO	cadre;

	cadre.x = pix_x;
	cadre.y = pix_y;
	cadre.l = object_ptr->l;
	cadre.h = object_ptr->h;
	cadre.backgc = RSC_skin_ptr->map_color (object_ptr->c);
	INTR_graph_ptr->display_xorbox (&cadre);

	if (object_ptr->header.attributes & RSC_ATTR_DISABLE)
	{
		INTR_graph_ptr->disable_zone (pix_x, pix_y, object_ptr->l, object_ptr->h, RSC_skin_ptr->map_color (0));
	}
}



void	RSC_display_object_bitmap (int pix_x, int pix_y, const RSC_OBJTYPE_BITMAP *object_ptr)
{
	int		width;
	int		height;
	const UBYTE	*data_ptr;
	Image		*pic_ptr;
	bool		disable_flag;
	bool		selected_flag;

	pic_ptr = RSC_get_button_picture_ptr (&object_ptr->header, object_ptr->img [0], disable_flag, selected_flag);
	width = pic_ptr->get_width ();
	height = pic_ptr->get_height ();
	data_ptr = pic_ptr->get_data_ptr ();
	INTR_graph_ptr->put_image (data_ptr, pix_x, pix_y, width, height);

	if (object_ptr->header.attributes & RSC_ATTR_DISABLE)
	{
		INTR_graph_ptr->disable_zone (pix_x, pix_y, width, height, RSC_skin_ptr->map_color (Graphic::COL_GREY_DARK));
	}
}



void	RSC_display_object_tbitmap (int pix_x, int pix_y, const RSC_OBJTYPE_TBITMAP *object_ptr)
{
	int		width;
	int		height;
	const UBYTE	*data_ptr;
	Image		*pic_ptr;
	bool		disable_flag;
	bool		selected_flag;

	pic_ptr = RSC_get_button_picture_ptr (&object_ptr->header, object_ptr->img [0], disable_flag, selected_flag);
	width = pic_ptr->get_width ();
	height = pic_ptr->get_height ();
	data_ptr = pic_ptr->get_data_ptr ();
	INTR_graph_ptr->put_image (data_ptr, pix_x, pix_y, width, height, 255);

	if (object_ptr->header.attributes & RSC_ATTR_DISABLE)
	{
		INTR_graph_ptr->disable_zone (pix_x, pix_y, width, height, RSC_skin_ptr->map_color (Graphic::COL_GREY_DARK));
	}
}



void	RSC_display_object_text (int pix_x, int pix_y, const RSC_OBJTYPE_TEXT *object_ptr)
{
	INTR_graph_ptr->display_string (object_ptr->text_0,
	                               pix_x, pix_y, RSC_skin_ptr->map_color (object_ptr->c));

	if (object_ptr->header.attributes & RSC_ATTR_DISABLE)
	{
		INTR_graph_ptr->disable_zone (pix_x, pix_y,
		                              int (strlen (object_ptr->text_0)) * RSC_CHAR_W,
							               RSC_CHAR_H, RSC_skin_ptr->map_color (0));
	}
}



void	RSC_display_object_ttext (int pix_x, int pix_y, const RSC_OBJTYPE_TTEXT *object_ptr)
{
	INTR_graph_ptr->display_string_transp (object_ptr->text_0,
	                                      pix_x, pix_y, RSC_skin_ptr->map_color (object_ptr->c));

	if (object_ptr->header.attributes & RSC_ATTR_DISABLE)
	{
		INTR_graph_ptr->disable_zone (pix_x, pix_y,
		                              int (strlen (object_ptr->text_0)) * RSC_CHAR_W,
							               RSC_CHAR_H, RSC_skin_ptr->map_color (0));
	}
}



void	RSC_display_object_intbox (int pix_x, int pix_y, const RSC_OBJTYPE_INTBOX *object_ptr)
{
	Graphic_FRAME_INFO	cadre;
	const Skin_SpecialElt	*elt_ptr;
	int		color_type;
	bool		disable_flag;

	cadre.x = pix_x;
	cadre.y = pix_y;
	cadre.l = object_ptr->l;
	cadre.h = object_ptr->h;

	switch (object_ptr->t)
	{

	/* Gris */
	case	RSC_INTBOX_T_GREY:
		color_type = 0;
		cadre.backgc = 9;
		cadre.nborderc = 9;
		if (object_ptr->header.attributes & RSC_ATTR_SELECTED)
		{
			cadre.lborderc = 8;
			cadre.sborderc = 10;
		}
		else
		{
			cadre.lborderc = 10;
			cadre.sborderc = 8;
		}
		break;

	/* Gris-bleu */
	case	RSC_INTBOX_T_BLUE:
	default:
		color_type = 1;
		cadre.backgc = 13;
		cadre.nborderc = 13;
		if (object_ptr->header.attributes & RSC_ATTR_SELECTED)
		{
			cadre.lborderc = 12;
			cadre.sborderc = 14;
		}
		else
		{
			cadre.lborderc = 14;
			cadre.sborderc = 12;
		}
		break;
	}

	elt_ptr = RSC_skin_ptr->get_special_elt (Skin_SPEC_ELT_FRAME, color_type);
	RSC_display_tiled_pic ((const RSC_OBJTYPE_HEADER *)object_ptr, elt_ptr, &cadre, disable_flag, false, false);

	if (disable_flag)
	{
		INTR_graph_ptr->disable_zone (pix_x, pix_y,
		                             object_ptr->l, object_ptr->h,
		                             RSC_skin_ptr->map_color (cadre.sborderc));
	}
}



void	RSC_display_object_extbox (int pix_x, int pix_y, const RSC_OBJTYPE_EXTBOX *object_ptr)
{
	Graphic_FRAME_INFO	cadre;
	const Skin_SpecialElt	*elt_ptr;
	int		color_type;
	bool		disable_flag;

	cadre.x = pix_x;
	cadre.y = pix_y;
	cadre.l = object_ptr->l;
	cadre.h = object_ptr->h;

	switch (object_ptr->t)
	{

	/* Noir enfonce, bords gris */
	case	RSC_EXTBOX_T_BLACKG:
		color_type = 0;
		cadre.backgc = 0;
		cadre.nborderc = 9;
		cadre.lborderc = 8;
		cadre.sborderc = 10;
		break;

	/* Noir enfonce, bord gris-bleus */
	case	RSC_EXTBOX_T_BLACKB:
		color_type = 1;
		cadre.backgc = 0;
		cadre.nborderc = 13;
		cadre.lborderc = 12;
		cadre.sborderc = 14;
		break;

	/* Bleu enfonce, bords gris */
	case	RSC_EXTBOX_T_BLUEG:
		color_type = 0;
		cadre.backgc = 1;
		cadre.nborderc = 9;
		cadre.lborderc = 8;
		cadre.sborderc = 10;
		break;

	/* Bleu enfonce, bord gris-bleus */
	case	RSC_EXTBOX_T_BLUEB:
	default:
		color_type = 1;
		cadre.backgc = 1;
		cadre.nborderc = 13;
		cadre.lborderc = 12;
		cadre.sborderc = 14;
		break;
	}

	elt_ptr = RSC_skin_ptr->get_special_elt (Skin_SPEC_ELT_TEXT_FIELD, color_type);
	RSC_display_tiled_pic ((const RSC_OBJTYPE_HEADER *)object_ptr, elt_ptr, &cadre, disable_flag, true, true);

	if (disable_flag)
	{
		INTR_graph_ptr->disable_zone (pix_x, pix_y, object_ptr->l, object_ptr->h, RSC_skin_ptr->map_color (cadre.sborderc));
	}
}



void	RSC_display_object_boxtext (int pix_x, int pix_y, const RSC_OBJTYPE_BOXTEXT *object_ptr)
{
	Graphic_FRAME_INFO	cadre;
	int		str_pixxpos;
	int		l_char;
	char		*text_0;
	const Skin_SpecialElt	*elt_ptr;
	int		color_type;
	bool		disable_flag;
	
	cadre.x = pix_x;
	cadre.y = pix_y;
	cadre.l = object_ptr->l;
	cadre.h = object_ptr->h;

	switch (object_ptr->t)
	{
	/* Gris */
	case	RSC_BOXTEXT_T_GREY:
		color_type = 0;
		cadre.backgc = 9;
		cadre.nborderc = 9;
		if (object_ptr->header.attributes & RSC_ATTR_SELECTED)
		{
			cadre.lborderc = 8;
			cadre.sborderc = 10;
		}
		else
		{
			cadre.lborderc = 10;
			cadre.sborderc = 8;
		}
		break;

	/* Gris-bleu */
	case	RSC_BOXTEXT_T_BLUE:
	default:
		color_type = 1;
		cadre.backgc = 13;
		cadre.nborderc = 13;
		if (object_ptr->header.attributes & RSC_ATTR_SELECTED)
		{
			cadre.lborderc = 12;
			cadre.sborderc = 14;
		}
		else
		{
			cadre.lborderc = 14;
			cadre.sborderc = 12;
		}
		break;
	}

	elt_ptr = RSC_skin_ptr->get_special_elt (Skin_SPEC_ELT_BUTTON, color_type);
	RSC_display_tiled_pic ((const RSC_OBJTYPE_HEADER *)object_ptr, elt_ptr, &cadre, disable_flag, false, false);

	text_0 = object_ptr->text_0;
	switch (object_ptr->j)
	{
	/* Centre */
	case	RSC_BOXTEXT_J_CENTER:
		str_pixxpos = pix_x + ((  object_ptr->l
										- int (strlen (text_0)) * RSC_CHAR_W) / 2);
		break;
	/* Gauche */
	case	RSC_BOXTEXT_J_LEFT:
		str_pixxpos = pix_x + RSC_CHAR_W / 2;
		break;
	/* Droite */
	case	RSC_BOXTEXT_J_RIGHT:
		str_pixxpos =   pix_x + object_ptr->l
						  - int (strlen (text_0)) * RSC_CHAR_W
						  - RSC_CHAR_W / 2;
		break;
	}

	l_char = cadre.l / RSC_CHAR_W;
	INTR_graph_ptr->display_string_transp_shadow (text_0, str_pixxpos,
	                                             pix_y + (cadre.h - RSC_CHAR_H) / 2,
	                                             RSC_skin_ptr->map_color (cadre.lborderc),
	                                             RSC_skin_ptr->map_color (cadre.sborderc),
	                                             l_char);

	if (disable_flag)
	{
		INTR_graph_ptr->disable_zone (pix_x, pix_y,
		                             object_ptr->l, object_ptr->h,
		                             RSC_skin_ptr->map_color (cadre.sborderc));
	}
}



void	RSC_display_object_edboxtext (int pix_x, int pix_y, const RSC_OBJTYPE_EDBOXTEXT *object_ptr)
{
	int		l_char;
	Graphic_FRAME_INFO	cadre;
	const Skin_SpecialElt	*elt_ptr;
	int		color_type;
	bool		disable_flag;

	cadre.x = pix_x;
	cadre.y = pix_y;
	cadre.l = object_ptr->l;
	cadre.h = RSC_CHAR_H;

	switch (object_ptr->t)
	{
	/* Noir enfonc‚ aux bords gris */
	case	RSC_EDBOXTEXT_T_GREY:
		color_type = 0;
		cadre.backgc = 0;
		cadre.nborderc = 9;
		cadre.lborderc = 8;
		cadre.sborderc = 10;
		break;
	/* Noir enfonc‚ aux bords gris-bleus */
	case	RSC_EDBOXTEXT_T_BLUE:
	default:
		color_type = 1;
		cadre.backgc = 0;
		cadre.nborderc = 13;
		cadre.lborderc = 12;
		cadre.sborderc = 14;
		break;
	}

	elt_ptr = RSC_skin_ptr->get_special_elt (Skin_SPEC_ELT_TEXT_FIELD, color_type);
	RSC_display_tiled_pic ((const RSC_OBJTYPE_HEADER *)object_ptr, elt_ptr, &cadre, disable_flag, true, true);

	l_char = cadre.l / RSC_CHAR_W;
	INTR_graph_ptr->display_string (object_ptr->text_0,
	                               pix_x, pix_y,
	                               RSC_skin_ptr->map_color (1),
	                               RSC_skin_ptr->map_color (0), l_char);

	if (object_ptr->header.attributes & RSC_ATTR_DISABLE)
	{
		INTR_graph_ptr->disable_zone (pix_x, pix_y, object_ptr->l,
		                             RSC_CHAR_H, RSC_skin_ptr->map_color (cadre.sborderc));
	}
}



void	RSC_display_object_button (int pix_x, int pix_y, const RSC_OBJTYPE_BUTTON *object_ptr)
{
	int		width;
	int		height;
	Graphic_FRAME_INFO	cadre;
	const UBYTE	*data_ptr;
	bool		disable_flag;
	bool		selected_flag;
	Image		*pic_ptr;
	const Skin_SpecialElt	*elt_ptr;
	int		color_type;
	bool		disable_flag_2;

	cadre.x = pix_x;
	cadre.y = pix_y;
	cadre.l = RSC_CHAR_W * 2;
	cadre.h = RSC_BOXTEXT_H;
	width = cadre.l;
	height = cadre.h;
	disable_flag = false;
	disable_flag_2 = false;

	switch	(object_ptr->t2)
	{
	case	RSC_BUTTON_T2_GREY:
		color_type = 0;
		cadre.backgc = 9;
		cadre.nborderc = 9;
		if (object_ptr->header.attributes & RSC_ATTR_SELECTED)
		{
			cadre.lborderc = 8;
			cadre.sborderc = 10;
		}
		else
		{
			cadre.lborderc = 10;
			cadre.sborderc = 8;
		}
		break;

	case	RSC_BUTTON_T2_BLUE:
	default:
		color_type = 1;
		cadre.backgc = 13;
		cadre.nborderc = 13;
		if (object_ptr->header.attributes & RSC_ATTR_SELECTED)
		{
			cadre.lborderc = 12;
			cadre.sborderc = 14;
		}
		else
		{
			cadre.lborderc = 14;
			cadre.sborderc = 12;
		}
		break;
	}

	elt_ptr = RSC_skin_ptr->get_special_elt (Skin_SPEC_ELT_BUTTON, color_type);

	switch (object_ptr->t)
	{
	/* Fleche vers le haut */
	case	RSC_BUTTON_T_UARROW:
		RSC_display_tiled_pic ((const RSC_OBJTYPE_HEADER *)object_ptr, elt_ptr, &cadre, disable_flag, false, false);
		INTR_graph_ptr->display_string_transp_shadow ("\xFC", pix_x + RSC_CHAR_W / 2,
		                                             pix_y + (RSC_BOXTEXT_H - RSC_CHAR_H) / 2,
		                                             RSC_skin_ptr->map_color (cadre.lborderc),
		                                             RSC_skin_ptr->map_color (cadre.sborderc));
		break;
	/* Fleche vers le bas */
	case	RSC_BUTTON_T_DARROW:
		RSC_display_tiled_pic ((const RSC_OBJTYPE_HEADER *)object_ptr, elt_ptr, &cadre, disable_flag, false, false);
		INTR_graph_ptr->display_string_transp_shadow ("\xFD", pix_x + RSC_CHAR_W / 2,
		                                             pix_y + (RSC_BOXTEXT_H - RSC_CHAR_H) / 2,
		                                             RSC_skin_ptr->map_color (cadre.lborderc),
		                                             RSC_skin_ptr->map_color (cadre.sborderc));
		break;
	/* Fleche vers la gauche */
	case	RSC_BUTTON_T_LARROW:
		RSC_display_tiled_pic ((const RSC_OBJTYPE_HEADER *)object_ptr, elt_ptr, &cadre, disable_flag, false, false);
		INTR_graph_ptr->display_string_transp_shadow ("\xFF", pix_x + RSC_CHAR_W / 2,
		                                             pix_y + (RSC_BOXTEXT_H - RSC_CHAR_H) / 2,
		                                             RSC_skin_ptr->map_color (cadre.lborderc),
		                                             RSC_skin_ptr->map_color (cadre.sborderc));
		break;
	/* Fleche vers la droite */
	case	RSC_BUTTON_T_RARROW:
		RSC_display_tiled_pic ((const RSC_OBJTYPE_HEADER *)object_ptr, elt_ptr, &cadre, disable_flag, false, false);
		INTR_graph_ptr->display_string_transp_shadow ("\xFE", pix_x + RSC_CHAR_W / 2,
		                                             pix_y + (RSC_BOXTEXT_H - RSC_CHAR_H) / 2,
		                                             RSC_skin_ptr->map_color (cadre.lborderc),
		                                             RSC_skin_ptr->map_color (cadre.sborderc));
		break;
	/* Boutons avec image */
	default:
		pic_ptr = RSC_get_button_picture_ptr (&object_ptr->header, object_ptr->img [0], disable_flag_2, selected_flag);
		width = pic_ptr->get_width ();
		height = pic_ptr->get_height ();
		data_ptr = pic_ptr->get_data_ptr ();
		cadre.l = width;
		cadre.h = height;
		RSC_display_tiled_pic ((const RSC_OBJTYPE_HEADER *)object_ptr, elt_ptr, &cadre, disable_flag, false, false);
		INTR_graph_ptr->put_image (data_ptr, pix_x, pix_y, width, height, 255);
		break;
	}

	if (disable_flag || disable_flag_2)
	{
		INTR_graph_ptr->disable_zone (pix_x, pix_y, width, height, RSC_skin_ptr->map_color (cadre.sborderc));
	}
}



/*==========================================================================*/
/*      Nom:                                                                */
/*      Description:                                                        */
/*      Parametres en entree:                                               */
/*      Parametres en sortie:                                               */
/*      Parametres en entree/sortie:                                        */
/*      Retour:                                                             */
/*==========================================================================*/

signed long	RSC_get_button_picture_nbr (const RSC_OBJTYPE_HEADER *object_ptr, int elt, bool &disable_flag, bool &selected_flag)
{
	disable_flag = ((object_ptr->attributes & RSC_ATTR_DISABLE) != 0);
	selected_flag =  ((object_ptr->attributes & RSC_ATTR_SELECTED) != 0);

	return (RSC_skin_ptr->get_pic_nbr (elt, selected_flag, disable_flag));
}



Image	*RSC_get_button_picture_ptr (const RSC_OBJTYPE_HEADER *object_ptr, int elt, bool &disable_flag, bool &selected_flag)
{
	long		pic;

	pic = RSC_get_button_picture_nbr (object_ptr, elt, disable_flag, selected_flag);
	if (pic < 0)
	{
		return (NULL);
	}

	return (RSC_skin_ptr->get_pic_ptr (pic));
}



void	RSC_display_image (Image *image_ptr, int src_x, int src_y, int src_w, int src_h, int object, int dest_x, int dest_y)
{
	if (src_w < 0)
	{
		src_w = image_ptr->get_width () - src_x;
		src_w = MAX (src_w, 0);
	}
	if (src_h < 0)
	{
		src_h = image_ptr->get_height () - src_y;
		src_h = MAX (src_h, 0);
	}

	INTR_graph_ptr->hide_mouse ();
	INTR_graph_ptr->put_rectangle (image_ptr->get_data_ptr (), image_ptr->get_width (),
	                              src_x, src_y, src_w, src_h,
	                              RSC_absolute_object_pixxpos [object] + dest_x,
	                              RSC_absolute_object_pixypos [object] + dest_y);
	INTR_graph_ptr->unlock_screen ();
}



void	RSC_display_image (Image *image_ptr, int src_x, int src_y, int src_w, int src_h, int object, int dest_x, int dest_y, int t_color)
{
	if (src_w < 0)
	{
		src_w = image_ptr->get_width () - src_x;
		src_w = MAX (src_w, 0);
	}
	if (src_h < 0)
	{
		src_h = image_ptr->get_height () - src_y;
		src_h = MAX (src_h, 0);
	}

	INTR_graph_ptr->hide_mouse ();
	INTR_graph_ptr->put_rectangle (image_ptr->get_data_ptr (), image_ptr->get_width (),
	                              src_x, src_y, src_w, src_h,
	                              RSC_absolute_object_pixxpos [object] + dest_x,
	                              RSC_absolute_object_pixypos [object] + dest_y,
	                              t_color);
	INTR_graph_ptr->unlock_screen ();
}



void	RSC_display_point (int object, int x, int y, int color)
{
	if (   x >= 0 && x < RSC_get_width (object)
	    && y >= 0 && y < RSC_get_height (object))
	{
		INTR_graph_ptr->display_point (RSC_absolute_object_pixxpos [object] + x,
		                               RSC_absolute_object_pixypos [object] + y,
		                               color);
	}
}



void	RSC_display_line (int object, int x1, int y1, int x2, int y2, int color, LWORD pattern)
{
	int		width;
	int		height;
	double	xx1;
	double	yy1;
	double	xx2;
	double	yy2;

	width = RSC_get_width (object);
	height = RSC_get_height (object);
	if (width < 1 || height < 1)
	{
		return;
	}

	xx1 = x1;
	yy1 = y1;
	xx2 = x2;
	yy2 = y2;

/*______________________________________________
 *
 * Clipping horizontal
 *______________________________________________
 */

	if (xx1 > xx2)
	{
		BASE_swap (xx1, xx2);
		BASE_swap (yy1, yy2);
	}

	/* Bord gauche */
	if (xx1 < 0 && xx2 < 0)
	{
		return;
	}
	else if (xx1 < 0)
	{
		yy1 += (yy2 - yy1) * (-xx1) / (xx2 - xx1);
		xx1 = 0;
	}

	/* Bord droit */
	if (xx1 > width-1 && xx2 > width-1)
	{
		return;
	}
	else if (xx2 > width-1)
	{
		yy2 += (yy2 - yy1) * (width-1 - xx2) / (xx2 - xx1);
		xx2 = width-1;
	}

/*______________________________________________
 *
 * Clipping vertical
 *______________________________________________
 */

	if (yy1 > yy2)
	{
		BASE_swap (xx1, xx2);
		BASE_swap (yy1, yy2);
	}

	/* Bord haut */
	if (yy1 < 0 && yy2 < 0)
	{
		return;
	}
	else if (yy1 < 0)
	{
		xx1 += (xx2 - xx1) * (-yy1) / (yy2 - yy1);
		yy1 = 0;
	}

	/* Bord bas */
	if (yy1 > height-1 && yy2 > height-1)
	{
		return;
	}
	else if (yy2 > height-1)
	{
		xx2 += (xx2 - xx1) * (height-1 - yy2) / (yy2 - yy1);
		yy2 = height-1;
	}

	INTR_graph_ptr->display_line (RSC_absolute_object_pixxpos [object] + (int) floor (xx1),
	                              RSC_absolute_object_pixypos [object] + (int) floor (yy1),
	                              RSC_absolute_object_pixxpos [object] + (int) floor (xx2),
	                              RSC_absolute_object_pixypos [object] + (int) floor (yy2),
	                              color, pattern);
}



void	RSC_display_tiled_pic (const RSC_OBJTYPE_HEADER *object_ptr, const Skin_SpecialElt *elt_ptr, Graphic_FRAME_INFO *cadre_ptr, bool &disable_flag, bool ext_flag, bool fill_flag)
{
	Image		*pic_ptr;
	signed long	pic;
	signed long	elt;
	bool		selected_flag;
	bool		pic_flag;
	const Skin_TileData	*tile_info_ptr;
	int		pic_width;
	int		pic_height;
	int		corner_w [2];
	int		corner_h [2];
	int		cur_pos [2];
	int		start_pos [2];
	int		end_pos [2];
	int		nbr_tiles [2];
	int		cur_tile_x;
	int		cur_tile_y;
	signed int	dif [2];
	signed int	half_dif;
	const UBYTE	*data_ptr;
	const Skin_RECTANGLE	*rect_ptr;
	Graphic_FRAME_INFO	old_cadre;

	elt = -1;
	if (elt_ptr != NULL)
	{
		elt = elt_ptr->elt;
	}

	pic_flag = false;
	if (elt >= 0)
	{
		pic = RSC_get_button_picture_nbr (object_ptr, elt, disable_flag, selected_flag);
		if (pic >= 0)
		{
			pic_ptr = RSC_skin_ptr->get_pic_ptr (pic);
			pic_width = pic_ptr->get_width ();
			pic_height = pic_ptr->get_height ();
			data_ptr = pic_ptr->get_data_ptr ();
			tile_info_ptr = RSC_skin_ptr->get_tile_info (pic);
			rect_ptr = &tile_info_ptr->rect [Skin_RECT_TILE];

			if (fill_flag)
			{
				old_cadre = *cadre_ptr;
			}

			/* Si c'est un cadre a bord exterieur, on agrandit le cadre
				de facon a l'afficher comme un cadre interieur. */
			if (ext_flag)
			{
				cadre_ptr->x -= tile_info_ptr->rect [Skin_RECT_CENTER].x;
				cadre_ptr->y -= tile_info_ptr->rect [Skin_RECT_CENTER].y;
				cadre_ptr->l += pic_width - tile_info_ptr->rect [Skin_RECT_CENTER].l;
				cadre_ptr->h += pic_width - tile_info_ptr->rect [Skin_RECT_CENTER].h;
			}

			/* Largeur */
			dif [0] = cadre_ptr->l - (pic_width - rect_ptr->l);
			if (dif [0] < 0)
			{
				half_dif = (-dif [0]) / 2;
				corner_w [0] = rect_ptr->x - half_dif;
				corner_w [1] = cadre_ptr->l - corner_w [0];
			}
			else
			{
				corner_w [0] = rect_ptr->x;
				corner_w [1] = pic_width - rect_ptr->l - rect_ptr->x;
			}

			/* Hauteur */
			dif [1] = cadre_ptr->h - (pic_height - rect_ptr->h);
			if (dif [1] < 0)
			{
				half_dif = (-dif [1]) / 2;
				corner_h [0] = rect_ptr->y - half_dif;
				corner_h [1] = cadre_ptr->h - corner_h [0];
			}
			else
			{
				corner_h [0] = rect_ptr->y;
				corner_h [1] = pic_height - rect_ptr->h - rect_ptr->y;
			}
			end_pos [0] = cadre_ptr->x + cadre_ptr->l - corner_w [1];
			end_pos [1] = cadre_ptr->y + cadre_ptr->h - corner_h [1];

			/* Affichage des coins */
			INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
			                               0, 0,
			                               corner_w [0], corner_h [0],
			                               cadre_ptr->x, cadre_ptr->y, 255);
			INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
			                               pic_width - corner_w [1], 0,
			                               corner_w [1], corner_h [0],
			                               end_pos [0], cadre_ptr->y, 255);
			INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
			                               0, pic_height - corner_h [1],
			                               corner_w [0], corner_h [1],
			                               cadre_ptr->x, end_pos [1], 255);
			INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
			                               pic_width - corner_w [1], pic_height - corner_h [1],
			                               corner_w [1], corner_h [1],
			                               end_pos [0], end_pos [1], 255);

			/* Affichage des bordure haut et bas */
			if (dif [0] > 0)
			{
				start_pos [0] = cadre_ptr->x + corner_w [0];
				nbr_tiles [0] = (cadre_ptr->l - corner_w [0] - corner_w [1] - 1) / rect_ptr->l;
				cur_pos [0] = start_pos [0];
				for (cur_tile_x = 0; cur_tile_x < nbr_tiles [0]; cur_tile_x ++)
				{
					INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
					                               rect_ptr->x, 0,
					                               rect_ptr->l, corner_h [0],
					                               cur_pos [0], cadre_ptr->y, 255);
					INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
					                               rect_ptr->x, pic_height - corner_h [1],
					                               rect_ptr->l, corner_h [1],
					                               cur_pos [0], end_pos [1], 255);
					cur_pos [0] += rect_ptr->l;
				}
				INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
				                               rect_ptr->x, 0,
				                               end_pos [0] - cur_pos [0], corner_h [0],
				                               cur_pos [0], cadre_ptr->y, 255);
				INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
				                               rect_ptr->x, pic_height - corner_h [1],
				                               end_pos [0] - cur_pos [0], corner_h [1],
				                               cur_pos [0], end_pos [1], 255);
			}

			/* Affichage des bordure gauches et droites */
			if (dif [1] > 0)
			{
				start_pos [1] = cadre_ptr->y + corner_h [0];
				nbr_tiles [1] = (cadre_ptr->h - corner_h [0] - corner_h [1] - 1) / rect_ptr->h;
				cur_pos [1] = start_pos [1];
				for (cur_tile_y = 0; cur_tile_y < nbr_tiles [1]; cur_tile_y ++)
				{
					INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
					                               0, rect_ptr->y,
					                               corner_w [0], rect_ptr->h,
					                               cadre_ptr->x, cur_pos [1], 255);
					INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
					                               pic_width - corner_w [1], rect_ptr->y,
					                               corner_w [1], rect_ptr->h,
					                               end_pos [0], cur_pos [1], 255);
					cur_pos [1] += rect_ptr->h;
				}
				INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
				                               0, rect_ptr->y,
				                               corner_w [0], end_pos [1] - cur_pos [1],
				                               cadre_ptr->x, cur_pos [1], 255);
				INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
				                               pic_width - corner_w [1], rect_ptr->y,
				                               corner_w [1], end_pos [1] - cur_pos [1],
				                               end_pos [0], cur_pos [1], 255);
			}

			/* Affichage du centre */
			if (! fill_flag)
			{
				if (   dif [0] > 0
				    && dif [1] > 0)
				{
					cur_pos [1] = start_pos [1];
					for (cur_tile_y = 0; cur_tile_y < nbr_tiles [1]; cur_tile_y ++)
					{
						cur_pos [0] = start_pos [0];
						for (cur_tile_x = 0; cur_tile_x < nbr_tiles [0]; cur_tile_x ++)
						{
							INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
							                               rect_ptr->x, rect_ptr->y,
							                               rect_ptr->l, rect_ptr->h,
							                               cur_pos [0], cur_pos [1], 255);
							cur_pos [0] += rect_ptr->l;
						}
						INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
						                               rect_ptr->x, rect_ptr->y,
						                               end_pos [0] - cur_pos [0], rect_ptr->h,
						                               cur_pos [0], cur_pos [1], 255);

						cur_pos [1] += rect_ptr->h;
					}	

					cur_pos [0] = start_pos [0];
					for (cur_tile_x = 0; cur_tile_x < nbr_tiles [0]; cur_tile_x ++)
					{
						INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
						                               rect_ptr->x, rect_ptr->y,
						                               rect_ptr->l, end_pos [1] - cur_pos [1],
						                               cur_pos [0], cur_pos [1], 255);
						cur_pos [0] += rect_ptr->l;
					}

					INTR_graph_ptr->put_rectangle (data_ptr, pic_width,
					                               rect_ptr->x, rect_ptr->y,
					                               end_pos [0] - cur_pos [0], end_pos [1] - cur_pos [1],
					                               cur_pos [0], cur_pos [1], 255);
				}
			}

			else
			{
				old_cadre.backgc = RSC_skin_ptr->map_color (old_cadre.backgc);
				INTR_graph_ptr->display_box (&old_cadre);
			}

			pic_flag = true;
		}
	}

	if (! pic_flag)
	{
		disable_flag = ((object_ptr->attributes & RSC_ATTR_DISABLE) != 0);
		if (ext_flag)
		{
			INTR_graph_ptr->display_cadre_ext (cadre_ptr);
		}
		else
		{
			INTR_graph_ptr->display_cadre_int (cadre_ptr);
		}
	}
}



/*==========================================================================*/
/*      Nom:                                                                */
/*      Description:                                                        */
/*      Parametres en entree:                                               */
/*      Parametres en sortie:                                               */
/*      Parametres en entree/sortie:                                        */
/*      Retour:                                                             */
/*==========================================================================*/

