1 //       _________ __                 __
2 //      /   _____//  |_____________ _/  |______     ____  __ __  ______
3 //      \_____  \\   __\_  __ \__  \\   __\__  \   / ___\|  |  \/  ___/
4 //      /        \|  |  |  | \// __ \|  |  / __ \_/ /_/  >  |  /\___ |
5 //     /_______  /|__|  |__|  (____  /__| (____  /\___  /|____//____  >
6 //             \/                  \/          \//_____/            \/
7 //  ______________________                           ______________________
8 //                        T H E   W A R   B E G I N S
9 //         Stratagus - A free fantasy real time strategy game engine
10 //
11 /**@name mng.cpp - The mng graphic file loader. */
12 //
13 //      (c) Copyright 2004-2005 by Jimmy Salmon
14 //
15 //      This program is free software; you can redistribute it and/or modify
16 //      it under the terms of the GNU General Public License as published by
17 //      the Free Software Foundation; only version 2 of the License.
18 //
19 //      This program is distributed in the hope that it will be useful,
20 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //      GNU General Public License for more details.
23 //
24 //      You should have received a copy of the GNU General Public License
25 //      along with this program; if not, write to the Free Software
26 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 //      02111-1307, USA.
28 //
29 
30 //@{
31 
32 /*----------------------------------------------------------------------------
33 --  Includes
34 ----------------------------------------------------------------------------*/
35 
36 #include "stratagus.h"
37 
38 #ifdef USE_MNG
39 
40 #include "video.h"
41 #include "iolib.h"
42 #include "iocompat.h"
43 
44 /*----------------------------------------------------------------------------
45 --  Functions
46 ----------------------------------------------------------------------------*/
47 
my_alloc(mng_size_t len)48 static mng_ptr MNG_DECL my_alloc(mng_size_t len)
49 {
50 	char *ptr = new char[len];
51 	memset(ptr, 0, len);
52 	return (mng_ptr)ptr;
53 }
54 
my_free(mng_ptr ptr,mng_size_t)55 static void MNG_DECL my_free(mng_ptr ptr, mng_size_t)
56 {
57 	delete[] static_cast<char *>(ptr);
58 }
59 
my_openstream(mng_handle handle)60 static mng_bool MNG_DECL my_openstream(mng_handle handle)
61 {
62 	Mng *mng;
63 
64 	mng = (Mng *)mng_get_userdata(handle);
65 	mng->fd = fopen(mng->name.c_str(), "rb");
66 	if (!mng->fd) {
67 		return MNG_FALSE;
68 	}
69 	return MNG_TRUE;
70 }
71 
my_closestream(mng_handle handle)72 static mng_bool MNG_DECL my_closestream(mng_handle handle)
73 {
74 	Mng *mng;
75 
76 	mng = (Mng *)mng_get_userdata(handle);
77 	if (mng->fd) {
78 		fclose(mng->fd);
79 	}
80 	return MNG_TRUE;
81 }
82 
my_readdata(mng_handle handle,mng_ptr buf,mng_uint32 buflen,mng_uint32p read)83 static mng_bool MNG_DECL my_readdata(mng_handle handle, mng_ptr buf, mng_uint32 buflen,
84 									 mng_uint32p read)
85 {
86 	Mng *mng;
87 
88 	mng = (Mng *)mng_get_userdata(handle);
89 	*read = fread(buf, 1, buflen, mng->fd);
90 	return MNG_TRUE;
91 }
92 
my_processheader(mng_handle handle,mng_uint32 width,mng_uint32 height)93 static mng_bool MNG_DECL my_processheader(mng_handle handle, mng_uint32 width,
94 										  mng_uint32 height)
95 {
96 	mng_imgtype type = mng_get_sigtype(handle);
97 	if (type != mng_it_mng) {
98 		return TRUE;
99 	}
100 
101 	Mng *mng = (Mng *)mng_get_userdata(handle);
102 
103 	// Allocate the SDL surface to hold the image
104 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
105 	const Uint32 Rmask = 0x000000FF;
106 	const Uint32 Gmask = 0x0000FF00;
107 	const Uint32 Bmask = 0x00FF0000;
108 #else
109 	const Uint32 Rmask = 0xFF000000 >> 8;
110 	const Uint32 Gmask = 0x00FF0000 >> 8;
111 	const Uint32 Bmask = 0x0000FF00 >> 8;
112 #endif
113 
114 	mng->buffer = new unsigned char[width * height * 3];
115 	memset(mng->buffer, width * height * 3, sizeof(unsigned char));
116 
117 	mng->surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height,
118 										8 * 3, Rmask, Gmask, Bmask, 0);
119 	if (mng->surface == NULL) {
120 		fprintf(stderr, "Out of memory");
121 		exit(1);
122 	}
123 
124 	return MNG_TRUE;
125 }
126 
my_getcanvasline(mng_handle handle,mng_uint32 linenr)127 static mng_ptr MNG_DECL my_getcanvasline(mng_handle handle, mng_uint32 linenr)
128 {
129 	Mng *mng;
130 
131 	mng = (Mng *)mng_get_userdata(handle);
132 	return mng->buffer + linenr * mng->surface->w * 3;
133 }
134 
my_refresh(mng_handle handle,mng_uint32,mng_uint32,mng_uint32,mng_uint32)135 static mng_bool MNG_DECL my_refresh(mng_handle handle, mng_uint32, mng_uint32,
136 									mng_uint32, mng_uint32)
137 {
138 	Mng *mng = (Mng *)mng_get_userdata(handle);
139 	SDL_LockSurface(mng->surface);
140 	for (int i = 0; i < mng->surface->h; ++i) {
141 		memcpy((char *)mng->surface->pixels + i * mng->surface->pitch,
142 			   mng->buffer + i * mng->surface->w * 3, mng->surface->w * 3);
143 	}
144 	SDL_UnlockSurface(mng->surface);
145 
146 	return MNG_TRUE;
147 }
148 
my_gettickcount(mng_handle)149 static mng_uint32 MNG_DECL my_gettickcount(mng_handle)
150 {
151 	return GetTicks();
152 }
153 
my_settimer(mng_handle handle,mng_uint32 msecs)154 static mng_bool MNG_DECL my_settimer(mng_handle handle, mng_uint32 msecs)
155 {
156 	Mng *mng = (Mng *)mng_get_userdata(handle);
157 	mng->ticks = GetTicks() + msecs;
158 
159 	return MNG_TRUE;
160 }
161 
my_processmend(mng_handle handle,mng_uint32 iterationsdone,mng_uint32)162 static mng_bool MNG_DECL my_processmend(mng_handle handle, mng_uint32 iterationsdone,
163 										mng_uint32)
164 {
165 	Mng *mng = (Mng *)mng_get_userdata(handle);
166 	mng->iteration = iterationsdone;
167 
168 	return MNG_TRUE;
169 }
170 
my_errorproc(mng_handle handle,mng_int32,mng_int8,mng_chunkid,mng_uint32,mng_int32,mng_int32,mng_pchar errortext)171 static mng_bool MNG_DECL my_errorproc(mng_handle handle, mng_int32,
172 									  mng_int8, mng_chunkid, mng_uint32, mng_int32, mng_int32, mng_pchar errortext)
173 {
174 	Mng *mng = (Mng *)mng_get_userdata(handle);
175 	mng->iteration = 0x7fffffff;
176 	if (errortext) {
177 		DebugPrint("MNG error: %s\n" _C_ errortext);
178 	}
179 	return TRUE;
180 }
181 
182 
Mng()183 Mng::Mng() :
184 	name(NULL), fd(NULL), handle(NULL), surface(NULL), buffer(NULL),
185 	ticks(0), iteration(0), is_dirty(false)
186 {
187 }
188 
189 
~Mng()190 Mng::~Mng()
191 {
192 	//	delete[] name;
193 	if (handle) {
194 		mng_cleanup(&handle);
195 	}
196 	if (surface) {
197 		SDL_FreeSurface(surface);
198 	}
199 	delete[] buffer;
200 }
201 
202 
203 /**
204 **  Display a MNG
205 **
206 **  @param x  X coordinate
207 **  @param y  Y coordinate
208 */
Draw(int x,int y)209 void Mng::Draw(int x, int y)
210 {
211 	if (ticks <= GetTicks()) {
212 		mng_display_resume(handle);
213 	}
214 
215 	SDL_Rect rect = {(short int)x, (short int)y, (short unsigned int)(surface->w), (short unsigned int)(surface->h)};
216 	SDL_BlitSurface(surface, NULL, TheScreen, &rect);
217 }
218 
219 /**
220 **  Load a MNG
221 **
222 **  @param name  Name of the MNG file
223 */
Load(const std::string & name)224 bool Mng::Load(const std::string &name)
225 {
226 	this->name = LibraryFileName(name.c_str());
227 	handle = mng_initialize(this, my_alloc, my_free, MNG_NULL);
228 	if (handle == MNG_NULL) {
229 		return false;
230 	}
231 	mng_setcb_openstream(handle, my_openstream);
232 	mng_setcb_closestream(handle, my_closestream);
233 	mng_setcb_readdata(handle, my_readdata);
234 	mng_setcb_processheader(handle, my_processheader);
235 	mng_setcb_processmend(handle, my_processmend);
236 	mng_setcb_getcanvasline(handle, my_getcanvasline);
237 	mng_setcb_refresh(handle, my_refresh);
238 	mng_setcb_gettickcount(handle, my_gettickcount);
239 	mng_setcb_settimer(handle, my_settimer);
240 	mng_setcb_errorproc(handle, my_errorproc);
241 
242 	mng_read(handle);
243 	if (surface && iteration != 0x7fffffff) {
244 		mng_display(handle);
245 	}
246 
247 	if (!surface || iteration == 0x7fffffff) {
248 		return false;
249 	}
250 	return true;
251 }
252 
253 /**
254 **  Reset a MNG
255 */
Reset()256 void Mng::Reset()
257 {
258 	mng_display_reset(handle);
259 	iteration = 0;
260 	mng_display(handle);
261 }
262 
_getData() const263 void* Mng::_getData() const
264 {
265 	if (ticks <= GetTicks()) {
266 		is_dirty = true;
267 		mng_display_resume(handle);
268 	} else {
269 		is_dirty = false;
270 	}
271 	return surface;
272 }
273 
274 #endif // USE_MNG
275 
276 //@}
277