1 /*
2  *  This file is part of Dune Legacy.
3  *
4  *  Dune Legacy is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  Dune Legacy is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with Dune Legacy.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef PALETTE_H
19 #define PALETTE_H
20 
21 #include <misc/exceptions.h>
22 
23 #include <SDL.h>
24 #include <string.h>
25 
26 class Palette
27 {
28     public:
Palette()29         Palette() : pSDLPalette(nullptr) {
30 
31         }
32 
Palette(int numPaletteEntries)33         explicit Palette(int numPaletteEntries) : pSDLPalette(nullptr) {
34             pSDLPalette = SDL_AllocPalette(numPaletteEntries);
35             if (!pSDLPalette) {
36                 throw;
37             }
38         }
39 
Palette(const SDL_Palette * pSDLPalette)40         explicit Palette(const SDL_Palette* pSDLPalette) : pSDLPalette(nullptr) {
41             setSDLPalette(pSDLPalette);
42         }
43 
Palette(const Palette & palette)44         Palette(const Palette& palette) : pSDLPalette(nullptr) {
45             *this = palette;
46         }
47 
~Palette()48         virtual ~Palette() {
49             deleteSDLPalette();
50         }
51 
52         Palette& operator=(const Palette& palette) {
53             if(this == &palette) {
54                 return *this;
55             }
56 
57             this->setSDLPalette(palette.pSDLPalette);
58 
59             return *this;
60         }
61 
62         inline SDL_Color& operator[](const int i) {
63             if(pSDLPalette == nullptr || i < 0 || i >= pSDLPalette->ncolors) {
64                 THROW(std::runtime_error, "Palette::operator[]: Invalid index!");
65             }
66 
67             return pSDLPalette->colors[i];
68         }
69 
70         inline const SDL_Color& operator[](const int i) const {
71             if(pSDLPalette == nullptr || i < 0 || i >= pSDLPalette->ncolors) {
72                 THROW(std::runtime_error, "Palette::operator[]: Invalid index!");
73             }
74 
75             return pSDLPalette->colors[i];
76         }
77 
getSDLPalette()78         inline SDL_Palette* getSDLPalette() const {
79             return pSDLPalette;
80         }
81 
setSDLPalette(const SDL_Palette * pSDLPalette)82         void setSDLPalette(const SDL_Palette* pSDLPalette) {
83             if(!pSDLPalette) {
84                 this->pSDLPalette = nullptr;
85                 return;
86             }
87             SDL_Palette* pNewSDLPalette = SDL_AllocPalette(pSDLPalette->ncolors);
88             if(!pNewSDLPalette) {
89                 throw;
90             }
91             memcpy(pNewSDLPalette->colors, pSDLPalette->colors, pSDLPalette->ncolors * sizeof(SDL_Color));
92 
93             deleteSDLPalette();
94             this->pSDLPalette = pNewSDLPalette;
95         }
96 
getNumColors()97         inline int getNumColors() const {
98             if(pSDLPalette == nullptr) {
99                 return 0;
100             }
101 
102             return pSDLPalette->ncolors;
103         }
104 
105         void applyToSurface(SDL_Surface* pSurface, int firstColor = 0, int endColor = -1) const {
106             Uint32 colorKey = 0;
107             bool hasColorKey = (SDL_GetColorKey(pSurface, &colorKey) == 0);
108 
109             if(pSDLPalette == nullptr) {
110                 THROW(std::runtime_error, "Palette::applyToSurface(): Palette not initialized yet!");
111             }
112 
113             if(pSurface == nullptr) {
114                 THROW(std::runtime_error, "Palette::applyToSurface(): pSurface == nullptr!");
115             }
116 
117             if(pSurface->format->palette == nullptr) {
118                 THROW(std::runtime_error, "Palette::applyToSurface(): Cannot apply palette to surface without a palette!");
119             }
120 
121             int nColors = (endColor != -1) ? (endColor - firstColor + 1) : (pSDLPalette->ncolors - firstColor);
122             SDL_SetPaletteColors(pSurface->format->palette, pSDLPalette->colors + firstColor, firstColor, nColors);
123 
124             if(hasColorKey) {
125                 SDL_SetColorKey(pSurface, SDL_TRUE, colorKey);
126             }
127         }
128 
129     private:
130 
deleteSDLPalette()131         void deleteSDLPalette() {
132             if (pSDLPalette != nullptr) {
133                 SDL_FreePalette(pSDLPalette);
134             }
135             pSDLPalette = nullptr;
136         }
137 
138         SDL_Palette* pSDLPalette;
139 };
140 
141 #endif // PALETTE_H
142