root/window/render.cc

Revision 65:4416cfac86ae, 14.4 KB (checked in by Thibaut Girka <thib@…>, 18 months ago)
Convert EUC-JP files to UTF8
Line 
1/*
2 * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 *    derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "font/font.h"
29#include "font/text.h"
30#include "SDL.h"
31#include "render.h"
32#include "rect.h"
33#include "surface.h"
34#include <stdio.h>
35
36#ifndef ALPHA_MAX
37#define ALPHA_MAX 255
38#endif
39
40Rect::Rect(const TextGlyph& letter) {
41        lx = letter.x + letter.glyph->bitmap_left;
42        rx = lx + letter.glyph->bitmap.width;
43
44        ty = letter.y - letter.glyph->bitmap_top;
45        by = ty + letter.glyph->bitmap.rows;
46}
47
48Rect::Rect(const class Surface& so) {
49        SDL_Surface* s = (SDL_Surface*)(&so);
50        lx = 0; ty = 0;
51        rx = s->w; by = s->h;
52}
53
54inline Rect _Rect(const SDL_Rect& r) {
55        return Rect(r.x, r.y, r.x+r.w, r.y+r.h);
56}
57
58inline SDL_Rect SDLed(const Rect& rect) {
59        SDL_Rect r;
60        r.x = rect.lx;
61        r.y = rect.ty;
62        r.w = rect.rx-rect.lx;
63        r.h = rect.by-rect.ty;
64        return r;
65}
66
67Rect DSurfaceRenderText(TextGlyphStream::iterator start, TextGlyphStream::iterator end, const Rect& srcrect,
68        Surface* dst_o, const Rect& dstrect) {
69
70        SDL_Surface* dst = (SDL_Surface*)dst_o;
71        Rect confine_to(srcrect);
72        Rect dst_clip(_Rect(dst->clip_rect));
73        Rect drawn_rect(0,0,0,0);
74
75        int dif_x = dstrect.lx - srcrect.lx;
76        int dif_y = dstrect.ty - srcrect.ty;
77
78        dst_clip.rmove(-dif_x, -dif_y);
79        confine_to.intersect(dst_clip);
80
81        TextGlyphStream::iterator it;
82        SDL_PixelFormat& fmt = *dst->format;
83        int ashift = fmt.Ashift - fmt.Aloss; int amask = fmt.Amask;
84        int dbpl = dst->pitch;
85        int dbpp = fmt.BytesPerPixel;
86
87        SDL_LockSurface(dst);
88        for (it=start; it!=end; it++) {
89                Rect letter_r(*it);
90                letter_r.intersect(confine_to);
91                if (letter_r.empty()) continue;
92                drawn_rect.join(letter_r);
93
94                int w = letter_r.width();
95                int h = letter_r.height();
96                int sbpl = it->glyph->bitmap.width;
97
98                unsigned char* smem = it->glyph->bitmap.buffer +
99                        (letter_r.ty - (it->y-it->glyph->bitmap_top)) * sbpl +
100                        (letter_r.lx - (it->x+it->glyph->bitmap_left));
101                char* dmem = (char*)dst->pixels + 
102                        (letter_r.ty + dif_y) * dbpl +
103                        (letter_r.lx + dif_x) * dbpp;
104                Uint32 pixel = ((int(it->r)<<fmt.Rshift)&fmt.Rmask) |((int(it->g)<<fmt.Gshift)&fmt.Gmask) |((int(it->b)<<fmt.Bshift)&fmt.Bmask);
105                int i,j;
106                if (!it->is_rev) {
107                        if (dbpp == 4) {
108                                for (i=0; i<h; i++) {
109                                        for (j=0; j<w; j++) {
110                                                int alpha = smem[j];
111                                                ((Uint32*)dmem)[j] = pixel | ((alpha << ashift)&amask);
112                                        }
113                                        smem += sbpl; dmem += dbpl;
114                                }
115                        } else if (dbpp == 2) {
116                                for (i=0; i<h; i++) {
117                                        for (j=0; j<w; j++) {
118                                                int alpha = smem[j];
119                                                ((Uint16*)dmem)[j] = pixel | ((alpha << ashift)&amask);
120                                        }
121                                        smem += sbpl; dmem += dbpl;
122                                }
123                        } else abort();
124                } else { /* reversed */
125                        if (dbpp == 4) {
126                                for (i=0; i<h; i++) {
127                                        for (j=0; j<w; j++) {
128                                                int alpha = 255 - smem[j];
129                                                ((Uint32*)dmem)[j] = pixel | ((alpha << ashift)&amask);
130                                        }
131                                        smem += sbpl; dmem += dbpl;
132                                }
133                        } else if (dbpp == 2) {
134                                for (i=0; i<h; i++) {
135                                        for (j=0; j<w; j++) {
136                                                int alpha = 255 - smem[j];
137                                                ((Uint16*)dmem)[j] = pixel | ((alpha << ashift)&amask);
138                                        }
139                                        smem += sbpl; dmem += dbpl;
140                                }
141                        } else abort();
142                }
143        }
144        SDL_UnlockSurface(dst);
145        drawn_rect.rmove(dif_x, dif_y);
146        return drawn_rect;
147}
148
149void DSurfaceFill(Surface* src_o, const Rect& rect, int r, int g, int b, int a) {
150        SDL_Rect sr = SDLed(rect); 
151        SDL_Surface* src = (SDL_Surface*)src_o;
152        SDL_FillRect( src, &sr, SDL_MapRGBA(src->format, r, g, b, a));
153}
154
155static void clip_rect(Rect& srcrect, Rect& dstrect, SDL_Surface* dstsurf) {
156        Rect confine_to(srcrect);
157        Rect dst_clip(_Rect(dstsurf->clip_rect));
158
159        int dif_x = dstrect.lx - srcrect.lx;
160        int dif_y = dstrect.ty - srcrect.ty;
161
162        dst_clip.rmove(-dif_x, -dif_y);
163        confine_to.intersect(dst_clip);
164
165        srcrect = confine_to;
166        dstrect = confine_to;
167        dstrect.rmove(dif_x, dif_y);
168}
169
170void DSurfaceMove(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o) {
171
172        SDL_Surface* dst = (SDL_Surface*)dst_o;
173        SDL_Surface* src = (SDL_Surface*)src_o;
174
175        if (dst->format->BytesPerPixel != src->format->BytesPerPixel) return; // RGB倉換はできない
176
177        Rect srcrect(srcrect_o), dstrect(dstrect_o);
178        clip_rect(srcrect, dstrect, dst);
179
180        SDL_LockSurface(dst); SDL_LockSurface(src);
181        int sbpl = src->pitch;
182        int dbpl = dst->pitch;
183        int bpp = dst->format->BytesPerPixel;
184        int width = bpp * srcrect.width();
185        int height = srcrect.height();
186        char* smem = src_o->mem(srcrect);
187        char* dmem = dst_o->mem(dstrect);
188        char* smem_end = src_o->mem_end(srcrect);
189        char* dmem_end = dst_o->mem_end(dstrect);
190
191        // メモリに重なりがあり、src が䞊䜍偎の堎合、コピヌ方向を逆転する
192        if (smem < dmem && dmem < smem_end) {
193                int i,j;
194                for (i=0; i<height; i++) {
195                        char* s = smem_end; char* d = dmem_end;
196                        for (j=0; j<width; j++)
197                                *--d = *--s;
198                        dmem_end -= dbpl; smem_end -= sbpl;
199                }
200        } else {
201                int i;
202                for (i=0; i<height; i++) {
203                        memcpy(dmem, smem, width);
204                        dmem += dbpl; smem += sbpl;
205                }
206        }
207        SDL_UnlockSurface(dst);
208        SDL_UnlockSurface(src);
209}
210
211void DSurfaceFillA(Surface* dsto, const Rect& rect, int r, int g, int b, int a) {
212        SDL_Surface* dst = (SDL_Surface*)dsto;
213        SDL_LockSurface( dst);
214        int dbpl = dst->pitch;
215        int bpp = dst->format->BytesPerPixel;
216        int width = rect.width();
217        int height = rect.height();
218        int amask = dst->format->Amask;
219        int ashift = dst->format->Ashift - dst->format->Aloss;
220
221        char* dmem = (char*)(dst->pixels) + rect.ty*dbpl + rect.lx*bpp;
222        unsigned int pixel = SDL_MapRGBA(dst->format, r, g, b, 0);
223        unsigned int pixela = SDL_MapRGBA(dst->format, r, g, b, a);
224        a += a>>7; /* 0-256 にする */
225        int i, j;
226        for (i=0; i<height; i++) {
227                char* d = dmem;
228                if (bpp == 4) {
229                        for (j=0; j<width; j++) {
230                                int alpha = (*(Uint32*)d)>>ashift;
231                                if (alpha == 0) (*(Uint32*)d) = pixel;
232                                else if (alpha == 255) *((Uint32*)d) = pixela;
233                                else { *((Uint32*)d) = pixel | ((((alpha*a)>>8)<<ashift)&amask); }
234                                d += bpp;
235                        }
236                } else if (bpp == 2) {
237                        for (j=0; j<width; j++) {
238                                int alpha = (*(Uint16*)d)>>ashift;
239                                if (alpha == 0) *((Uint16*)d) = pixel;
240                                else if (alpha == 255) *((Uint16*)d) = pixela;
241                                else { *((Uint16*)d) = pixel | ((((alpha*a)>>8)<<ashift)&amask); }
242                                d += bpp;
243                        }
244                }
245                dmem += dbpl;
246        }
247        SDL_UnlockSurface( dst);
248}
249
250#define ASHIFT 24
251#define CMASK1 0xff00ff
252#define CMASK2 0x00ff00
253
254inline void blit_pixel(Uint32* dest, Uint32* src, const unsigned char* alpha, bool use_srcalpha) {
255        Uint32 dest_value = *dest;
256        Uint32 src_value = *src;
257        Uint32 as = src_value >> ASHIFT;
258        if (as == 255 || (!use_srcalpha) ) {
259                as = *alpha;
260        } else {
261                as += (as >> 7); /* 0-0xff -> 0-0x100 */
262                as *= *alpha;
263                as >>= 8;
264        }
265        as += as >> 7;
266        // Isolate Red and Blue components
267        Uint32 src_c1 = src_value & CMASK1;
268        Uint32 dest_c1 = dest_value & CMASK1;
269        // Blend Red and Blue components
270        dest_c1 = (dest_c1 + (((src_c1-dest_c1) * as) >> 8)) & CMASK1;
271        // Isolate Green component
272        src_value &= CMASK2;
273        dest_value &= CMASK2;
274        // Blend Green component
275        dest_value = (dest_value + (((src_value-dest_value) * as) >> 8)) & CMASK2;
276        // Put it alltogether
277        *dest = dest_c1 | dest_value | 0xff000000;
278}
279
280static void blit_line(Uint32* dest, Uint32* src, const unsigned char* alpha,int ax0, int ax1, int awidth, int aj0, int aj1, bool use_srcalpha) {
281        int j;
282        int ax = ax0;
283        const unsigned char* a = alpha + ax0;
284        if (awidth == 1) { //  わりずよくあるので最適化
285                for (j=aj0; j < aj1; j++) {
286                        blit_pixel(dest++, src++, alpha, use_srcalpha);
287                }
288        }
289        else
290        {
291                for (j=aj0; j < aj1; j++) {
292                        for (; ax<awidth; ax++)
293                                blit_pixel(dest++, src++, a++, use_srcalpha);
294                        ax = 0;
295                        a = alpha;
296                }
297                for (; ax < ax1; ax++)
298                        blit_pixel(dest++, src++, a++, use_srcalpha);
299        }
300}
301
302void DSurfaceBlitAlpha(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, const unsigned char* alpha, const Rect& alpharect)
303{
304        SDL_Surface* dst = (SDL_Surface*)dst_o;
305        SDL_Surface* src = (SDL_Surface*)src_o;
306        SDL_PixelFormat& fmt = *dst->format;
307
308        Rect srcrect(srcrect_o), dstrect(dstrect_o);
309        clip_rect(srcrect, dstrect, dst);
310
311        int awidth = alpharect.width();
312        int aheight = alpharect.height();
313        if (awidth == 0 || aheight == 0) return;
314        int ax0 = srcrect.lx % awidth;
315        int ay0 = srcrect.ty % aheight;
316        int aj0 = srcrect.lx / awidth;
317        int ai0 = srcrect.ty / aheight;
318        int ax1 = srcrect.rx % awidth;
319        int ay1 = srcrect.by % aheight;
320        int aj1 = srcrect.rx / awidth;
321        int ai1 = srcrect.by / aheight;
322
323        SDL_LockSurface(dst);
324        SDL_LockSurface(src);
325        int dbpl = dst->pitch;
326        int sbpl = src->pitch;
327        int bpp = dst->format->BytesPerPixel;
328
329        char* dmem = dst_o->mem(dstrect);
330        char* smem = src_o->mem(srcrect);
331
332        const unsigned char* amem = alpha + ay0 * awidth;
333        int i;
334        int ay = ay0;
335        for (i = ai0; i < ai1; i++) {
336                for (; ay < aheight; ay++) {
337                        if (src->format->Amask == 0)
338                                blit_line( (Uint32*)dmem, (Uint32*)smem, amem,ax0, ax1, awidth, aj0, aj1, false);
339                        else
340                                blit_line( (Uint32*)dmem, (Uint32*)smem, amem,ax0, ax1, awidth, aj0, aj1, true);
341                        amem += awidth; dmem += dbpl; smem += sbpl;
342                }
343                ay = 0; amem = alpha;
344        }
345        for (; ay < ay1; ay++) {
346                if (src->format->Amask == 0)
347                        blit_line( (Uint32*)dmem, (Uint32*)smem, amem,ax0, ax1, awidth, aj0, aj1, false);
348                else
349                        blit_line( (Uint32*)dmem, (Uint32*)smem, amem,ax0, ax1, awidth, aj0, aj1, true);
350                amem += awidth; dmem += dbpl; smem += sbpl;
351        }
352        SDL_UnlockSurface(src);
353        SDL_UnlockSurface(dst);
354}
355
356void DSurfaceBlitAdd(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, unsigned char alpha) {
357        SDL_Surface* dst = (SDL_Surface*)dst_o;
358        SDL_Surface* src = (SDL_Surface*)src_o;
359
360        if (dst->format->BytesPerPixel != src->format->BytesPerPixel) return; // RGB倉換はできない
361
362        Rect srcrect(srcrect_o), dstrect(dstrect_o);
363        clip_rect(srcrect, dstrect, dst);
364
365        SDL_LockSurface(dst); SDL_LockSurface(src);
366        int sbpl = src->pitch;
367        int dbpl = dst->pitch;
368        int bpp = dst->format->BytesPerPixel;
369        int width = srcrect.width();
370        int height = srcrect.height();
371        char* smem = src_o->mem(srcrect);
372        char* dmem = dst_o->mem(dstrect);
373        char* smem_end = src_o->mem_end(srcrect);
374        char* dmem_end = dst_o->mem_end(dstrect);
375
376        SDL_PixelFormat& fmt = *dst->format;
377        int rshift = fmt.Rshift - fmt.Rloss; int rmask = fmt.Rmask;
378        int gshift = fmt.Gshift - fmt.Gloss; int gmask = fmt.Gmask;
379        int bshift = fmt.Bshift - fmt.Bloss; int bmask = fmt.Bmask;
380        int ashift = src->format->Ashift - src->format->Aloss; int amask = src->format->Amask;
381        int allmask = rmask | gmask | bmask;
382        int i, j;
383        for (i=0; i < height; i++) {
384                char* d = dmem; char* s = smem;
385                for (j=0; j < width; j++) {
386                        Uint32 sd = *(Uint32*)s;
387                        Uint32 dd = *(Uint32*)d;
388                        if (sd&allmask) {
389                                Uint32 sr = (sd&rmask)>>rshift;
390                                Uint32 sg = (sd&gmask)>>gshift;
391                                Uint32 sb = (sd&bmask)>>bshift;
392                                Uint32 alpha2 = alpha;
393                                if (amask)
394                                {
395                                        alpha2 = ((sd&amask)>>ashift);
396                                        alpha2 += alpha2 >> 7;
397                                        alpha2 *= alpha;
398                                        alpha2 >>= 8;
399                                }
400                               
401                                if (alpha2 != ALPHA_MAX) {
402                                        sr = (sr*alpha2)>>8;
403                                        sg = (sg*alpha2)>>8;
404                                        sb = (sb*alpha2)>>8;
405                                }
406                                Uint32 dr = sr + ((dd&rmask)>>rshift);
407                                Uint32 dg = sg + ((dd&gmask)>>gshift);
408                                Uint32 db = sb + ((dd&bmask)>>bshift);
409                                if (dr > 255) dr = 255;
410                                if (dg > 255) dg = 255;
411                                if (db > 255) db = 255;
412                                *(Uint32*)d = ((dr<<rshift)&rmask)| ((dg<<gshift)&gmask)| ((db<<bshift)&bmask);
413                        }
414                        s += bpp; d += bpp;
415                }
416                dmem += dbpl; smem += sbpl;
417        }
418        SDL_UnlockSurface(src);
419        SDL_UnlockSurface(dst);
420}
421
422void DSurfaceBlitMultiply(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o) {
423        SDL_Surface* dst = (SDL_Surface*)dst_o;
424        SDL_Surface* src = (SDL_Surface*)src_o;
425
426        Rect srcrect(srcrect_o), dstrect(dstrect_o);
427        clip_rect(srcrect, dstrect, dst);
428
429        SDL_LockSurface(dst);
430        SDL_LockSurface(src);
431        int dbpl = dst->pitch;
432        int sbpl = src->pitch;
433        int bpp = dst->format->BytesPerPixel;
434        int width = srcrect.width();
435        int height = srcrect.height();
436        char* dmem = dst_o->mem(dstrect);
437        char* smem = src_o->mem(srcrect);
438
439        SDL_PixelFormat& fmt = *dst->format;
440        /* dst の 0-255 を 0-pixel に倉換する積算 */
441        int i;
442        int table1[256], table2[256], table3[256];
443        Uint32 src_pixel = *(Uint32*)smem;
444        src_pixel |= 0xff000000;
445        int c1=src_pixel&255, c2=(src_pixel>>8)&255, c3=(src_pixel>>16)&255;
446        for (i=0; i<256; i++) {
447                int n = i + (i>>7);
448                table1[i] = (c1*n)>>8;
449                table2[i] = (c2*n)&0xff00;
450                table3[i] = ((c3*n)<<8) & 0xff0000;
451        }
452        int err_count = 0;
453        for (i=0; i<height; i++) {
454                Uint32* d = (Uint32*)dmem;
455                Uint32* s = (Uint32*)smem;
456                int j; for (j=0; j<width; j++) {
457                        Uint32 dd = *d;
458                        Uint32 ss = *s;
459                        if (ss == src_pixel) {
460                                *(Uint32*)d = table1[ dd & 0xff] | table2[ (dd>>8) & 0xff] | table3[ (dd>>16) & 0xff];
461                        } else if ( ((ss^src_pixel) & 0xffffff) == 0) { // r,g,b of ss == src_pixel
462                                Uint32 as = ss>>ASHIFT;
463                                as += as>>7;
464                                ss = table1[ dd & 0xff] | table2[ (dd>>8) & 0xff] | table3[ (dd>>16) & 0xff];
465                                Uint32 s1 = ss&CMASK1;
466                                Uint32 d1 = dd&CMASK1;
467                                d1 = (d1 + (((s1-d1) * as) >> 8)) & CMASK1;
468                                ss &= CMASK2;
469                                dd &= CMASK2;
470                                dd = (dd + (((ss-dd) * as) >> 8)) & CMASK2;
471                                *(Uint32*)d = d1 | dd | 0xff000000;
472                        } else err_count++;
473                        d++; s++;
474                }
475                dmem += dbpl; smem += sbpl;
476        }
477        if (err_count) {
478                fprintf(stderr,"multipy_blit : surface does not have unique color(%08x); %d pixels in width %d, height %d\n",
479                        src_pixel, err_count, width, height);
480        }
481        SDL_UnlockSurface(dst);
482        SDL_UnlockSurface(src);
483}
Note: See TracBrowser for help on using the browser.