1 /*
2 ** wolfmapcommon.cpp
3 **
4 **---------------------------------------------------------------------------
5 ** Copyright 2013 Braden Obrzut
6 ** All rights reserved.
7 **
8 ** Redistribution and use in source and binary forms, with or without
9 ** modification, are permitted provided that the following conditions
10 ** are met:
11 **
12 ** 1. Redistributions of source code must retain the above copyright
13 ** notice, this list of conditions and the following disclaimer.
14 ** 2. Redistributions in binary form must reproduce the above copyright
15 ** notice, this list of conditions and the following disclaimer in the
16 ** documentation and/or other materials provided with the distribution.
17 ** 3. The name of the author may not be used to endorse or promote products
18 ** derived from this software without specific prior written permission.
19 **
20 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 **---------------------------------------------------------------------------
31 **
32 **
33 */
34
35 #include "wolfmapcommon.h"
36
37 // Only important thing to remember is that both
38 // Compression methods work on WORDs rather than bytes.
39
ExpandCarmack(const unsigned char * in,unsigned char * out)40 void FMapLump::ExpandCarmack(const unsigned char* in, unsigned char* out)
41 {
42 const unsigned char* const end = out + ReadLittleShort((const BYTE*)in);
43 const unsigned char* const start = out;
44 in += 2;
45
46 const unsigned char* copy;
47 BYTE length;
48 while(out < end)
49 {
50 length = *in++;
51 if(length == 0 && (*in == CARMACK_NEARTAG || *in == CARMACK_FARTAG))
52 {
53 *out++ = in[1];
54 *out++ = in[0];
55 in += 2;
56 continue;
57 }
58 else if(*in == CARMACK_NEARTAG)
59 {
60 copy = out-(in[1]*2);
61 in += 2;
62 }
63 else if(*in == CARMACK_FARTAG)
64 {
65 copy = start+(ReadLittleShort((const BYTE*)(in+1))*2);
66 in += 3;
67 }
68 else
69 {
70 *out++ = length;
71 *out++ = *in++;
72 continue;
73 }
74 if(out+(length*2) > end)
75 break;
76 while(length-- > 0)
77 {
78 *out++ = *copy++;
79 *out++ = *copy++;
80 }
81 }
82 }
83
ExpandRLEW(const unsigned char * in,unsigned char * out,const DWORD length,const WORD rlewTag)84 void FMapLump::ExpandRLEW(const unsigned char* in, unsigned char* out, const DWORD length, const WORD rlewTag)
85 {
86 const unsigned char* const end = out+length;
87
88 while(out < end)
89 {
90 if(ReadLittleShort((const BYTE*)in) != rlewTag)
91 {
92 *out++ = *in++;
93 *out++ = *in++;
94 }
95 else
96 {
97 WORD count = ReadLittleShort((const BYTE*)(in+2));
98 WORD input = ReadLittleShort((const BYTE*)(in+4));
99 in += 6;
100 while(count-- > 0)
101 {
102 WriteLittleShort((BYTE*)out, input);
103 out += 2;
104 }
105 }
106 }
107 }
108
FillCache()109 int FMapLump::FillCache()
110 {
111 if(LumpSize == 0)
112 return 1;
113
114 unsigned int PlaneSize = Header.Width*Header.Height*2;
115
116 Cache = new char[LumpSize];
117 strcpy(Cache, "WDC3.1");
118 WriteLittleShort((BYTE*)&Cache[10], rtlMap ? 4 : 3);
119 WriteLittleShort((BYTE*)&Cache[12], 16);
120 WriteLittleShort((BYTE*)&Cache[HEADERSIZE-4], Header.Width);
121 WriteLittleShort((BYTE*)&Cache[HEADERSIZE-2], Header.Height);
122 memcpy(&Cache[14], Header.Name, 16);
123
124 // Read map data and expand it
125 unsigned char* output = reinterpret_cast<unsigned char*>(Cache+HEADERSIZE);
126 for(unsigned int i = 0;i < PLANES;++i)
127 {
128 // ChaosEdit HACK: Likely in order to save a few bytes ChaosEdit sets
129 // the second and third map plane offsets to be the same (since vanilla
130 // doesn't use the data). If we see this we need to zero fill the plane.
131 if(i == 2 && Header.PlaneOffset[1] == Header.PlaneOffset[2] && !rtlMap)
132 {
133 memset(output, 0, PlaneSize);
134 output += PlaneSize;
135 continue;
136 }
137
138 unsigned char* input = new unsigned char[Header.PlaneLength[i]];
139 Owner->Reader->Seek(Header.PlaneOffset[i], SEEK_SET);
140 Owner->Reader->Read(input, Header.PlaneLength[i]);
141
142 if(carmackCompressed)
143 {
144 unsigned char* tempOut = new unsigned char[ReadLittleShort((BYTE*)input)];
145 ExpandCarmack(input, tempOut);
146 ExpandRLEW(tempOut+2, output, ReadLittleShort((const BYTE*)tempOut), rlewTag);
147 delete[] tempOut;
148 }
149 else
150 ExpandRLEW(input, output, PlaneSize, rlewTag);
151
152 delete[] input;
153 output += PlaneSize;
154
155 // RTL maps don't have a floor/ceiling texture plane so insert one
156 // We do this after the things plane has been read
157 if(rtlMap && i == 1)
158 {
159 const WORD floorTex = ReadLittleShort((const BYTE*)(Cache+HEADERSIZE))-0xB4;
160 const WORD ceilingTex = ReadLittleShort((const BYTE*)(Cache+HEADERSIZE+2))-0xC6;
161 const WORD fill = (floorTex&0xFF)|((ceilingTex&0xFF)<<8);
162 WORD *out = reinterpret_cast<WORD*>(output);
163 for(unsigned int j = 0;j < PlaneSize/2;++j)
164 *out++ = fill;
165 output += PlaneSize;
166 }
167 }
168 return 1;
169 }
170