ok
[xonotic/netradiant.git] / plugins / imagehl / sprite.cpp
1 /*
2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 // by Hydra - hydra@hydras-world.com
23
24 #include "sprite.h"
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29
30 typedef unsigned char byte;
31
32 #include "ifilesystem.h"
33
34 #include "imagelib.h"
35
36 /*
37 ============================================================================
38
39 IDSP IMAGE (.spr files)
40
41 Some code copied straight from the Q1 source, also used the HalfLife SDK as
42 a reference.
43
44 ============================================================================
45 */
46
47 typedef enum {ST_SYNC=0, ST_RAND } synctype_t;
48 typedef enum { SPR_SINGLE=0, SPR_GROUP } spriteframetype_t;
49
50 typedef struct dspriteheader_s {
51         int                     ident;
52         int                     version;
53 } dspriteheader_t;
54
55 // Quake1
56 typedef struct {
57         int                     type;
58         float           boundingradius;
59         int                     width;
60         int                     height;
61         int                     numframes;
62         float           beamlength;
63         synctype_t      synctype;
64 } dspritev1_t;
65
66 // Halflife
67 typedef struct {
68         int                     type;
69         int                     texFormat;
70         float           boundingradius;
71         int                     width;
72         int                     height;
73         int                     numframes;
74         float           beamlength;
75         synctype_t   synctype;
76 } dspritev2_t;
77
78 typedef struct {
79         int                     origin[2];
80         int                     width;
81         int                     height;
82 } dspriteframe_t;
83
84 typedef struct {
85         short   type;
86 } dspriteframetype_t;
87
88 /*
89 typedef struct {
90   byte rgb[256][3];
91 } dpalette_t;
92 */
93
94 #define IDSPRITEHEADER  (('P'<<24)+('S'<<16)+('D'<<8)+'I')
95                                                                                                                 // little-endian "IDSP"
96
97 /*
98 =============
99 LoadIDSP
100 =============
101 */
102
103 Image* LoadIDSPBuff(byte *buffer)
104 {
105   byte *buf_p;
106   int columns, rows, numPixels;
107   byte *pixbuf;
108
109   int row, column;
110   byte *palette;
111         unsigned char red, green, blue, alphabyte;
112
113   dspriteheader_t *header;
114         dspritev1_t                     *pinv1;
115         dspritev2_t                     *pinv2;
116         dspriteframetype_t      *pframetype;
117         int                                     version;
118         int                                     numframes;
119   dspriteframe_t *spriteframe;
120
121   header = (dspriteheader_t *)buffer;
122
123   if (header->ident != IDSPRITEHEADER)
124   {
125     globalErrorStream() << "WARNING: IDSP file has wrong header\n";
126     return 0;
127   }
128   
129   version = header->version;
130         if (version != 1 && version != 2 )
131   {
132     globalErrorStream() << "WARNING: IDSP file has wrong version number "
133                                  "(" << version << " should be 1 or 2)\n";
134     return 0;
135   }
136
137   // initialise variables depending on the sprite version.
138   switch (version)
139   {
140     case 1:
141             pinv1 = (dspritev1_t *)(header+1);
142       numframes = pinv1->numframes;
143       columns = pinv1->width;
144       rows = pinv1->height;
145         pframetype = (dspriteframetype_t *)(pinv1 + 1);
146       break;
147     case 2:
148             pinv2 = (dspritev2_t *)(header+1);
149       numframes = pinv2->numframes;
150       columns = pinv2->width;
151       rows = pinv2->height;
152         pframetype = (dspriteframetype_t *)(pinv2 + 1);      
153       break;
154     default:
155       globalErrorStream() << "WARNING: IDSP file has unsupported version\n";
156       return 0;
157   }
158   if (numframes > 1)
159     globalErrorStream() << "WARNING: IDSP file has multiple frames, only the first frame will be used.\n";
160
161   // palette = buffer+mipdatasize+2;
162   // buf_p = buffer+lpMip->offsets[0];
163
164   numPixels = columns * rows;
165
166   RGBAImage* image = new RGBAImage(columns, rows);
167
168 #ifdef DEBUG
169         frametype = spriteframetype_t(pframetype->type);
170         if (frametype == SPR_SINGLE)
171   {
172     globalOutputStream() << "Single Frame\n";
173   }
174   else if (frametype == SPR_GROUP)
175   {
176     globalOutputStream() << "Group of Frames\n";
177   }
178   else
179   {
180     globalOutputStream() << "Bleh!\n"; // <-- we always get this, wtf!
181   }
182 #endif
183
184   palette = (byte *)(pframetype+1);
185   spriteframe = (dspriteframe_t *)(palette + (256*3) + 4); // what are those 4 extra bytes ? what's missing ?
186   buf_p = (byte *)(spriteframe + 1);
187
188   for (row = 0; row < rows; row++)
189   {
190     pixbuf = image->getRGBAPixels() + row * columns * 4;
191
192     for (column = 0; column < columns; column++)
193     {
194       int palIndex;
195
196             palIndex = *buf_p++;
197
198       red = *(palette+(palIndex*3));
199       green = *(palette+(palIndex*3)+1);
200       blue = *(palette+(palIndex*3)+2);
201
202       // HalfLife engine makes pixels that are BLUE transparent. (RGB = 0x0000FF)
203       // So show them that way in the editor.
204       if (blue == 0xff && red == 0x00 && green == 0x00)
205       {
206         alphabyte = 0xff; //FIXME: backwards? (so sprite models to render correctly)
207         blue = 0x00; // don't set the resulting pixel to blue
208       } 
209       else
210       {
211         alphabyte = 0x00; //FIXME: backwards? (so sprite models to render correctly)
212       }
213
214             *pixbuf++ = red;
215             *pixbuf++ = green;
216             *pixbuf++ = blue;
217
218             *pixbuf++ = alphabyte;
219     }
220   }
221
222   return image;
223 }
224
225 Image* LoadIDSP(ArchiveFile& file)
226 {
227   ScopedArchiveBuffer buffer(file);
228   return LoadIDSPBuff( buffer.buffer );
229 }