1 /*
2 * OpenBOR - http://www.LavaLit.com
3 * -----------------------------------------------------------------------
4 * All rights reserved, see LICENSE in OpenBOR root for details.
5 *
6 * Copyright (c) 2004 - 2011 OpenBOR Team
7 */
8
9 /////////////////////////////////////////////////////////////////////////////
10 /*#include <stdio.h>
11 #include <string.h>*/
12 #include "globals.h"
13 #include "types.h"
14 #include "sprite.h"
15 #include "transform.h"
16 /////////////////////////////////////////////////////////////////////////////
17
18
putsprite_(unsigned char * dest,int x,int * linetab,int h,int screenwidth)19 static void putsprite_(
20 unsigned char *dest, int x, int *linetab, int h, int screenwidth
21 ) {
22 for(; h > 0; h--, dest += screenwidth) {
23 register int lx = x;
24 unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
25 while(lx < screenwidth) {
26 register int count = *data++;
27 if(count == 0xFF) break;
28 lx += count;
29 if(lx >= screenwidth) break;
30 count = *data++;
31 if(!count) continue;
32 if((lx + count) <= 0) { lx += count; data += count; continue; }
33 if(lx < 0) { count += lx; data -= lx; lx = 0; }
34 if((lx + count) > screenwidth) { count = screenwidth - lx; }
35 memcpy(dest+lx, data, count);
36 data+=count;lx+=count;
37 }
38 }
39 }
40
putsprite_flip_(unsigned char * dest,int x,int * linetab,int h,int screenwidth)41 static void putsprite_flip_(
42 unsigned char *dest, int x, int *linetab, int h, int screenwidth
43 ) {
44 for(; h > 0; h--, dest += screenwidth) {
45 register int lx = x;
46 unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
47 while(lx > 0) {
48 register int count = *data++;
49 if(count == 0xFF) break;
50 lx -= count;
51 if(lx <= 0) break;
52 count = *data++;
53 if(!count) continue;
54 if((lx - count) >= screenwidth) { lx -= count; data += count; continue; }
55 if(lx > screenwidth) { int diff = (lx - screenwidth); count -= diff; data += diff; lx = screenwidth; }
56 if((lx - count) < 0) { count = lx; }
57 //for(; count > 0; count--) dest[--lx] = *data++;
58 lx--;
59 u8revcpy(dest+lx, data, count);
60 lx-=count-1;
61 data+=count;
62 }
63 }
64 }
65
putsprite_remap_(unsigned char * dest,int x,int * linetab,int h,int screenwidth,unsigned char * remap)66 static void putsprite_remap_(
67 unsigned char *dest, int x, int *linetab, int h, int screenwidth,
68 unsigned char *remap
69 ) {
70 for(; h > 0; h--, dest += screenwidth) {
71 register int lx = x;
72 unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
73 while(lx < screenwidth) {
74 register int count = *data++;
75 if(count == 0xFF) break;
76 lx += count;
77 if(lx >= screenwidth) break;
78 count = *data++;
79 if(!count) continue;
80 if((lx + count) <= 0) { lx += count; data += count; continue; }
81 if(lx < 0) { count += lx; data -= lx; lx = 0; }
82 if((lx + count) > screenwidth) { count = screenwidth - lx; }
83 //for(; count > 0; count--) dest[lx++] = remap[((int)(*data++))&0xFF];
84 u8pcpy(dest+lx, data, remap, count);
85 lx+=count;
86 data+=count;
87 }
88 }
89 }
90
putsprite_remap_flip_(unsigned char * dest,int x,int * linetab,int h,int screenwidth,unsigned char * remap)91 static void putsprite_remap_flip_(
92 unsigned char *dest, int x, int *linetab, int h, int screenwidth,
93 unsigned char *remap
94 ) {
95 for(; h > 0; h--, dest += screenwidth) {
96 register int lx = x;
97 unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
98 while(lx > 0) {
99 register int count = *data++;
100 if(count == 0xFF) break;
101 lx -= count;
102 if(lx <= 0) break;
103 count = *data++;
104 if(!count) continue;
105 if((lx - count) >= screenwidth) { lx -= count; data += count; continue; }
106 if(lx > screenwidth) { int diff = (lx - screenwidth); count -= diff; data += diff; lx = screenwidth; }
107 if((lx - count) < 0) { count = lx; }
108 //for(; count > 0; count--) dest[--lx] = remap[((int)(*data++))&0xFF];
109 lx--;
110 u8revpcpy(dest+lx, data, remap, count);
111 lx-=count-1;
112 data+=count;
113 }
114 }
115 }
116
117 //src high dest low
putsprite_remapblend_(unsigned char * dest,int x,int * linetab,int h,int screenwidth,unsigned char * remap,unsigned char * blend)118 static void putsprite_remapblend_(
119 unsigned char *dest, int x, int *linetab, int h, int screenwidth,
120 unsigned char*remap, unsigned char *blend
121 ) {
122 for(; h > 0; h--, dest += screenwidth) {
123 register int lx = x;
124 unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
125 while(lx < screenwidth) {
126 register int count = *data++;
127 if(count == 0xFF) break;
128 lx += count;
129 if(lx >= screenwidth) break;
130 count = *data++;
131 if(!count) continue;
132 if((lx + count) <= 0) { lx += count; data += count; continue; }
133 if(lx < 0) { count += lx; data -= lx; lx = 0; }
134 if((lx + count) > screenwidth) { count = screenwidth - lx; }
135 for(; count > 0; count--) { dest[lx] = blend[(remap[(((int)(*data++))&0xFF)]<<8)|dest[lx]]; lx++; }
136 }
137 }
138 }
139
putsprite_remapblend_flip_(unsigned char * dest,int x,int * linetab,int h,int screenwidth,unsigned char * remap,unsigned char * blend)140 static void putsprite_remapblend_flip_(
141 unsigned char *dest, int x, int *linetab, int h, int screenwidth,
142 unsigned char* remap, unsigned char *blend
143 ) {
144 for(; h > 0; h--, dest += screenwidth) {
145 register int lx = x;
146 unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
147 while(lx > 0) {
148 register int count = *data++;
149 if(count == 0xFF) break;
150 lx -= count;
151 if(lx <= 0) break;
152 count = *data++;
153 if(!count) continue;
154 if((lx - count) >= screenwidth) { lx -= count; data += count; continue; }
155 if(lx > screenwidth) { int diff = (lx - screenwidth); count -= diff; data += diff; lx = screenwidth; }
156 if((lx - count) < 0) { count = lx; }
157 for(; count > 0; count--) { --lx; dest[lx] = blend[(remap[(((int)(*data++))&0xFF)]<<8)|dest[lx]]; }
158 }
159 }
160 }
161
putsprite_blend_(unsigned char * dest,int x,int * linetab,int h,int screenwidth,unsigned char * blend)162 static void putsprite_blend_(
163 unsigned char *dest, int x, int *linetab, int h, int screenwidth,
164 unsigned char *blend
165 ) {
166 for(; h > 0; h--, dest += screenwidth) {
167 register int lx = x;
168 unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
169 while(lx < screenwidth) {
170 register int count = *data++;
171 if(count == 0xFF) break;
172 lx += count;
173 if(lx >= screenwidth) break;
174 count = *data++;
175 if(!count) continue;
176 if((lx + count) <= 0) { lx += count; data += count; continue; }
177 if(lx < 0) { count += lx; data -= lx; lx = 0; }
178 if((lx + count) > screenwidth) { count = screenwidth - lx; }
179 for(; count > 0; count--) { dest[lx] = blend[((((int)(*data++))&0xFF)<<8)|dest[lx]]; lx++; }
180 }
181 }
182 }
183
putsprite_blend_flip_(unsigned char * dest,int x,int * linetab,int h,int screenwidth,unsigned char * blend)184 static void putsprite_blend_flip_(
185 unsigned char *dest, int x, int *linetab, int h, int screenwidth,
186 unsigned char *blend
187 ) {
188 for(; h > 0; h--, dest += screenwidth) {
189 register int lx = x;
190 unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
191 while(lx > 0) {
192 register int count = *data++;
193 if(count == 0xFF) break;
194 lx -= count;
195 if(lx <= 0) break;
196 count = *data++;
197 if(!count) continue;
198 if((lx - count) >= screenwidth) { lx -= count; data += count; continue; }
199 if(lx > screenwidth) { int diff = (lx - screenwidth); count -= diff; data += diff; lx = screenwidth; }
200 if((lx - count) < 0) { count = lx; }
201 for(; count > 0; count--) { --lx; dest[lx] = blend[((((int)(*data++))&0xFF)<<8)|dest[lx]]; }
202 }
203 }
204 }
205
206 /////////////////////////////////////////////////////////////////////////////
207
putsprite_8(int x,int y,int is_flip,s_sprite * sprite,s_screen * screen,unsigned char * remap,unsigned char * blend)208 void putsprite_8(
209 int x, int y, int is_flip, s_sprite *sprite, s_screen *screen,
210 unsigned char *remap, unsigned char *blend
211 ) {
212 int *linetab;
213 int w, h;
214 unsigned char *dest;
215 // Get screen size
216 int screenwidth = screen->width;
217 int screenheight = screen->height;
218 // Adjust coords for centering
219 if(is_flip) x += sprite->centerx;
220 else x -= sprite->centerx;
221 y -= sprite->centery;
222 // Get sprite dimensions
223 w = sprite->width;
224 h = sprite->height;
225 // trivial clip all directions
226 if(is_flip)
227 {
228 if(x-w >= screenwidth) return;
229 if(x <= 0) return;
230 }
231 else
232 {
233 if(x >= screenwidth) return;
234 if((x+w) <= 0) return;
235 }
236 if(y >= screenheight) return;
237 if((y+h) <= 0) return;
238 // Init line table pointer
239 linetab = (int*)(sprite->data);
240 // clip top
241 if(y < 0) {
242 h += y; // subtract from height
243 linetab -= y; // add to linetab
244 y = 0; // add to y
245 }
246 // clip bottom
247 if((y+h) > screenheight) {
248 h = screenheight - y;
249 }
250 // calculate destination pointer
251 dest = ((unsigned char*)(screen->data)) + y*screenwidth;
252
253 if(blend&&remap){
254 if(is_flip) putsprite_remapblend_flip_(dest, x, linetab, h, screenwidth, remap, blend);
255 else putsprite_remapblend_ (dest, x , linetab, h, screenwidth,remap, blend);
256 } else if(blend) {
257 if(is_flip) putsprite_blend_flip_(dest, x, linetab, h, screenwidth, blend);
258 else putsprite_blend_ (dest, x , linetab, h, screenwidth, blend);
259 } else if(remap) {
260 if(is_flip) putsprite_remap_flip_(dest, x, linetab, h, screenwidth, remap);
261 else putsprite_remap_ (dest, x , linetab, h, screenwidth, remap);
262 } else {
263 if(is_flip) putsprite_flip_ (dest, x, linetab, h, screenwidth);
264 else putsprite_ (dest, x , linetab, h, screenwidth);
265 }
266 }
267
268 /////////////////////////////////////////////////////////////////////////////
269
270 // scalex scaley flipy ...
putsprite_ex(int x,int y,s_sprite * frame,s_screen * screen,s_drawmethod * drawmethod)271 void putsprite_ex(int x, int y, s_sprite *frame, s_screen *screen, s_drawmethod* drawmethod)
272 {
273 gfx_entry gfx;
274
275 if(!drawmethod->scalex || !drawmethod->scaley) return; // zero size
276
277 // no scale, no shift, no flip, no fill, so use common method
278 if(drawmethod->scalex==256 && drawmethod->scaley==256 && !drawmethod->flipy && !drawmethod->shiftx && drawmethod->fillcolor==TRANSPARENT_IDX && !drawmethod->rotate && !drawmethod->centerx && !drawmethod->centery)
279 {
280 switch(screen->pixelformat)
281 {
282 case PIXEL_8:
283 putsprite_8(x, y, drawmethod->flipx, frame, screen, drawmethod->table, drawmethod->alpha>0?blendtables[drawmethod->alpha-1]:NULL);
284 break;
285 case PIXEL_16:
286 putsprite_x8p16(x, y, drawmethod->flipx, frame, screen, (unsigned short*)drawmethod->table, drawmethod->alpha>0?blendfunctions16[drawmethod->alpha-1]:NULL);
287 break;
288 case PIXEL_32:
289 putsprite_x8p32(x, y, drawmethod->flipx, frame, screen, (unsigned*)drawmethod->table, drawmethod->alpha>0?blendfunctions32[drawmethod->alpha-1]:NULL);
290 break;
291 }
292 return;
293 }
294
295 gfx.type = gfx_sprite;
296 gfx.sprite = frame;
297
298 if(drawmethod->water.watermode==3){
299 gfx_draw_plane(screen, &gfx, x, y, frame->centerx, frame->centery, drawmethod);
300 }else if(drawmethod->water.watermode){
301 gfx_draw_water(screen, &gfx, x, y, frame->centerx, frame->centery, drawmethod);
302 }else if(drawmethod->rotate){
303 gfx_draw_rotate(screen, &gfx, x, y, frame->centerx, frame->centery, drawmethod);
304 }else{
305 gfx_draw_scale(screen, &gfx, x, y, frame->centerx, frame->centery, drawmethod);
306 }
307 }
308
putsprite(int x,int y,s_sprite * sprite,s_screen * screen,s_drawmethod * drawmethod)309 void putsprite(int x, int y, s_sprite* sprite, s_screen* screen, s_drawmethod* drawmethod)
310 {
311 if(!drawmethod || drawmethod->flag==0)
312 {
313 goto plainsprite;
314 }
315
316 putsprite_ex(x, y, sprite, screen, drawmethod);
317 return;
318 plainsprite:
319 switch(screen->pixelformat)
320 {
321 case PIXEL_8:
322 putsprite_8(x, y, 0, sprite, screen, NULL, NULL);
323 break;
324 case PIXEL_16:
325 putsprite_x8p16(x, y, 0, sprite, screen, (unsigned short*)sprite->palette, NULL);
326 break;
327 case PIXEL_32:
328 putsprite_x8p32(x, y, 0, sprite, screen, (unsigned*)sprite->palette, NULL);
329 break;
330 }
331 }
332
333
334
335 /////////////////////////////////////////////////////////////////////////////
336 //
337 // NULL for dest means do not actually encode
338 //
encodesprite(int centerx,int centery,s_bitmap * bitmap,s_sprite * dest)339 unsigned encodesprite(
340 int centerx, int centery,
341 s_bitmap *bitmap, s_sprite *dest
342 ) {
343 int x, x0, y, w, h;
344 unsigned char *data;
345 int *linetab;
346 unsigned char *src = bitmap->data;
347 int pb = PAL_BYTES, extrab;
348
349 if(bitmap->width <= 0 || bitmap->height <= 0){
350 // Image is empty (or bad), create an empty sprite
351 if(dest) {
352 //dest->is_flip_of = NULL;
353 dest->centerx = 0;
354 dest->centery = 0;
355 dest->width = 0;
356 dest->height = 0;
357 dest->pixelformat = bitmap->pixelformat;
358 dest->mask = NULL;
359 dest->palette = NULL;
360 }
361 return sizeof(s_sprite);
362 }
363
364 w = bitmap->width;
365 h = bitmap->height;
366
367 if(dest) {
368 //dest->is_flip_of = NULL;
369 dest->centerx = centerx;
370 dest->centery = centery;
371 dest->width = w;
372 dest->height = h;
373 dest->pixelformat = bitmap->pixelformat;
374 dest->mask = NULL;
375 }
376 linetab = (int*)(dest->data);
377 data = (unsigned char*)(linetab+h);
378
379 for(y = 0; y < h; y++, src += w) {
380 if(dest) { linetab[y] = ((size_t)data)-((size_t)(linetab+y)); }
381 x = 0;
382 for(;;) {
383 // search for the first visible pixel
384 x0 = x;
385 for(; (x < w) && ((x-x0)<0xFE); x++) { if(src[x]) break; }
386 // handle EOL
387 if(x >= w) { if(dest) { *data = 0xFF; } data++; break; }
388 // encode clearcount
389 if(dest) { *data = x-x0; } data++;
390 // if we're still not visible, encode a null visible count and continue
391 if(!src[x]) { if(dest) { *data = 0; } data++; continue; }
392 // search for the first invisible pixel
393 x0 = x;
394 for(; (x < w) && ((x-x0)<0xFF); x++) { if(!src[x]) break; }
395 // encode viscount and visible pixels
396 if(dest) {
397 *data++ = x-x0;
398 memcpy(data, src+x0, x-x0);
399 data += x-x0;
400 } else {
401 data += 1+(x-x0);
402 }
403 }
404 }
405
406 if(!bitmap->palette) pb = extrab = 0;
407 else
408 {
409 extrab = ((size_t)data)-((size_t)dest);
410 extrab %=4;
411 extrab = 4 - extrab;
412 extrab %=4;
413 }
414
415 //point palette to the last byte of the pixel data
416 if(dest)
417 {
418 if(bitmap->palette) // if the bitmap contains palette, copy it
419 {
420 dest->palette = ((unsigned char*)data) + extrab ;
421 memcpy(dest->palette, bitmap->palette, pb);
422 }
423 else dest->palette = NULL;
424 }
425 return ((size_t)data)-((size_t)dest)+ extrab + pb+ANYNUMBER;
426 }
427
428 /////////////////////////////////////////////////////////////////////////////
429
fakey_encodesprite(s_bitmap * bitmap)430 unsigned fakey_encodesprite(s_bitmap *bitmap) {
431 return encodesprite(0, 0, bitmap, NULL);
432 }
433
434 /////////////////////////////////////////////////////////////////////////////
435
436