Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

262 lines
7.1 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // palette.cpp
  4. //
  5. // Implements ramp palette code.
  6. //
  7. // Copyright (C) Microsoft Corporation, 1997.
  8. //
  9. //----------------------------------------------------------------------------
  10. #include "pch.cpp"
  11. #pragma hdrstop
  12. //-----------------------------------------------------------------------------
  13. //
  14. // RLDDIRampUpdateDDPalette
  15. //
  16. // Called before the destination DirectDraw surface is displayed, to set its palette.
  17. //
  18. //-----------------------------------------------------------------------------
  19. long RLDDIRampUpdateDDPalette(PD3DI_RASTCTX pCtx)
  20. {
  21. RLDDIRampLightingDriver* driver = (RLDDIRampLightingDriver*)pCtx->pRampDrv;
  22. if (driver->paletteChanged) {
  23. HRESULT ddrval;
  24. LPDIRECTDRAWPALETTE lpDDPal;
  25. ddrval = pCtx->pDDS->GetPalette(&lpDDPal);
  26. driver->paletteChanged = FALSE;
  27. if (lpDDPal) {
  28. PALETTEENTRY ddppe[256];
  29. DWORD i;
  30. ddrval = lpDDPal->GetEntries(0, 0, 256, ddppe);
  31. if (ddrval != DD_OK) {
  32. DPF_ERR("Failed to get palette entries from DirectDraw.");
  33. return ddrval;
  34. }
  35. // Update only those entries marked as free.
  36. for (i=0; i<256; i++) {
  37. if (!(ddppe[i].peFlags & (D3DPAL_READONLY | D3DPAL_RESERVED))) {
  38. ddppe[i] = driver->ddpalette[i];
  39. }
  40. }
  41. // Reset palette
  42. ddrval = lpDDPal->SetEntries(0, 0, 256, ddppe);
  43. if (ddrval != DD_OK)
  44. return ddrval;
  45. }
  46. }
  47. return DD_OK;
  48. }
  49. //
  50. // Set color in preparation to set the real palette
  51. //
  52. static void SetColor(void* arg, int index, int red, int green, int blue)
  53. {
  54. PD3DI_RASTCTX pCtx = (PD3DI_RASTCTX)arg;
  55. RLDDIRampLightingDriver* driver = (RLDDIRampLightingDriver*)pCtx->pRampDrv;
  56. driver->ddpalette[index].peRed = (BYTE)red;
  57. driver->ddpalette[index].peGreen = (BYTE)green;
  58. driver->ddpalette[index].peBlue = (BYTE)blue;
  59. //driver->ddpalette[index].peFlags = PC_RESERVED;
  60. driver->paletteChanged = TRUE;
  61. }
  62. RLDDIPalette* RLDDICreatePalette(PD3DI_RASTCTX pCtx, size_t size)
  63. {
  64. RLDDIPalette* pal;
  65. int i;
  66. if (D3DMalloc((void**) &pal, sizeof(RLDDIPalette)))
  67. return NULL;
  68. if (D3DMalloc((void**) &pal->entries,
  69. size * sizeof(RLDDIPaletteEntry)))
  70. {
  71. D3DFree(pal);
  72. return NULL;
  73. }
  74. pal->size = size;
  75. pal->priv = pCtx;
  76. pal->set_color = SetColor;
  77. pal->allocate_color = NULL;
  78. pal->free_color = NULL;
  79. LIST_INITIALIZE(&pal->free);
  80. LIST_INITIALIZE(&pal->unused);
  81. for (i = 0; i < HASH_SIZE; i++)
  82. LIST_INITIALIZE(&pal->hash[i]);
  83. for (i = size - 1; i >= 0; i--)
  84. {
  85. pal->entries[i].state = PALETTE_UNUSED;
  86. pal->entries[i].usage = 1;
  87. LIST_INSERT_ROOT(&pal->unused, &pal->entries[i], list);
  88. }
  89. pal->alloc.priv = pal;
  90. pal->alloc.allocate_color =
  91. (RLDDIColorAllocatorAllocateColor) RLDDIPaletteAllocateColor;
  92. pal->alloc.free_color =
  93. (RLDDIColorAllocatorFreeColor) RLDDIPaletteFreeColor;
  94. return pal;
  95. }
  96. void RLDDIPaletteSetColor(RLDDIPalette* pal,
  97. int index, int red, int green, int blue)
  98. {
  99. RLDDIPaletteEntry* entry;
  100. unsigned int hash = RGB_HASH(red, green, blue) % HASH_SIZE;
  101. entry = INDEX_TO_ENTRY(pal, index);
  102. /*
  103. * Snip out from its list (free, unused or some hash list).
  104. */
  105. LIST_DELETE(entry, list);
  106. entry->red = (BYTE)red;
  107. entry->green = (BYTE)green;
  108. entry->blue = (BYTE)blue;
  109. entry->state = PALETTE_USED;
  110. entry->usage = 1;
  111. LIST_INSERT_ROOT(&pal->hash[hash], entry, list);
  112. if (pal->set_color)
  113. {
  114. /*
  115. * Call lower level to set the color (hardware colormap or Windows
  116. * palette or whatever).
  117. */
  118. pal->set_color(pal->priv, index, red, green, blue);
  119. }
  120. }
  121. #define COLOR_MASK 0xF8
  122. int RLDDIPaletteAllocateColor(RLDDIPalette* pal,
  123. int red, int green, int blue)
  124. {
  125. RLDDIPaletteEntry* entry;
  126. unsigned int hash = RGB_HASH(red, green, blue) % HASH_SIZE;
  127. RLDDIPaletteEntry* best = NULL;
  128. size_t i;
  129. int closeness;
  130. for (entry = LIST_FIRST(&pal->hash[hash]); entry;
  131. entry = LIST_NEXT(entry,list))
  132. {
  133. if ((entry->red & COLOR_MASK) == (red & COLOR_MASK)
  134. && (entry->green & COLOR_MASK) == (green & COLOR_MASK)
  135. && (entry->blue & COLOR_MASK) == (blue & COLOR_MASK)
  136. && entry->state != PALETTE_UNUSED)
  137. {
  138. entry->usage++;
  139. return ENTRY_TO_INDEX(pal, entry);
  140. }
  141. }
  142. /*
  143. * Are there any free palette entries?
  144. */
  145. if (pal->allocate_color)
  146. {
  147. int index;
  148. index = pal->allocate_color(pal->priv, red, green, blue);
  149. if (index >= 0)
  150. {
  151. RLDDIPaletteSetColor(pal, index, red, green, blue);
  152. return index;
  153. }
  154. }
  155. else if (LIST_FIRST(&pal->free))
  156. {
  157. entry = LIST_FIRST(&pal->free);
  158. RLDDIPaletteSetColor(pal, ENTRY_TO_INDEX(pal, entry),
  159. red, green, blue);
  160. return ENTRY_TO_INDEX(pal, entry);
  161. }
  162. /*
  163. * No more colors available, return the closest.
  164. */
  165. closeness = INT_MAX;
  166. for (i = 0, entry = pal->entries; i < pal->size; i++, entry++)
  167. {
  168. int t;
  169. if (entry->state != PALETTE_USED) continue;
  170. #if 1
  171. {
  172. int t1,t2,t3;
  173. t1 = red - entry->red;
  174. t2 = green - entry->green;
  175. t3 = blue - entry->blue;
  176. t = (t1*t1 + t2*t2 + t3*t3);
  177. }
  178. #else
  179. t = (abs(red - entry->red)
  180. + abs(green - entry->green)
  181. + abs(blue - entry->blue));
  182. #endif
  183. if (t < closeness)
  184. {
  185. closeness = t;
  186. best = entry;
  187. }
  188. }
  189. best->usage++;
  190. /* *error = closeness; */
  191. return ENTRY_TO_INDEX(pal, best);
  192. }
  193. void RLDDIPaletteFreeColor(RLDDIPalette* pal, int index)
  194. {
  195. RLDDIPaletteEntry* entry;
  196. entry = INDEX_TO_ENTRY(pal, index);
  197. entry->usage--;
  198. if (entry->usage > 0) return;
  199. /*
  200. * Remove from whichever list it is on (pal->unused or pal->hash[])
  201. * and add to the free list.
  202. */
  203. LIST_DELETE(entry, list);
  204. if (pal->free_color)
  205. {
  206. pal->free_color(pal->priv, index);
  207. entry->state = PALETTE_UNUSED;
  208. LIST_INSERT_ROOT(&pal->unused, entry, list);
  209. }
  210. else
  211. {
  212. entry->state = PALETTE_FREE;
  213. LIST_INSERT_ROOT(&pal->free, entry, list);
  214. }
  215. }
  216. void RLDDIDestroyPalette(RLDDIPalette* pal)
  217. {
  218. RLDDIPaletteEntry* entry;
  219. size_t i;
  220. for (i = 0, entry = pal->entries; i < pal->size; i++, entry++)
  221. {
  222. if (entry->state != PALETTE_USED) continue;
  223. RLDDIPaletteFreeColor(pal, i);
  224. }
  225. D3DFree(pal->entries);
  226. D3DFree(pal);
  227. }