00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00043 #include "omicron/internal.h"
00044 #include "omicron/file.h"
00045 #include "omicron/render.h"
00046 #include "omicron/texture.h"
00047 #include "omicron/image.h"
00048
00049 #include <string>
00050
00051
00052
00053
00054
00055
00056
00057 image_c::image_c()
00058 {
00059 buf = NULL;
00060 buflen = 0;
00061 width = height = 0;
00062 bpp = 0;
00063 hasalpha = false;
00064 tex = INVALID_INDEX;
00065 dirty = true;
00066 }
00067
00068 image_c::~image_c()
00069 {
00070 AssertThis;
00071
00072 SafeArrayDelete(buf);
00073 }
00074
00075 void
00076 image_c::create
00077 (
00078 ushort x,
00079 ushort y
00080 )
00081 {
00082 AssertThis;
00083
00084 SafeArrayDelete(buf);
00085
00086 buflen = x*y*4;
00087 buf = new char[buflen*2];
00088 width = x;
00089 height = y;
00090 hasalpha = 0;
00091 bpp = 32;
00092 tex = INVALID_INDEX;
00093 dirty = true;
00094 }
00095
00096 bool
00097 image_c::load
00098 (
00099 const char * filename
00100 )
00101 {
00102 AssertThisV;
00103
00104 std::string szFilename = filename;
00105
00106 szFilename = szFilename + ".tga";
00107
00108 if (load_tga(szFilename.c_str()))
00109 return true;
00110
00111 dirty = true;
00112 return false;
00113 }
00114
00115
00116
00117
00118
00119 void
00120 image_c::mirror_vertical
00121 ()
00122 {
00123 AssertThis;
00124
00125 char *b = NULL;
00126
00127
00128 b = new char[ 4 * width ];
00129 AssertReturn1(b);
00130
00131
00132 for (sshort i=0; i<height/2; i++)
00133 {
00134 sshort h2 = height - i - 1;
00135
00136
00137 memcpy( b, buf+width * 4 * i, 4*width );
00138
00139
00140 memcpy( buf+width * 4 * i,
00141 buf+4*width * h2, 4*width );
00142
00143
00144 memcpy( buf + 4*width * h2, b, 4 * width );
00145 }
00146
00147 SafeArrayDelete(b);
00148 dirty = true;
00149 }
00150
00151
00152
00153
00154
00155
00156 void
00157 image_c::stamp
00158 (
00159 image_c * src,
00160 sshort x,
00161 sshort y
00162 )
00163 {
00164 AssertThis;
00165
00166 blt_blend(src, 0, 0, x-src->width/2, y-src->height/2, src->width, src->height, BT_BLEND);
00167 dirty = true;
00168 }
00169
00170 bool
00171 image_c::prepare_blt
00172 (
00173 image_c * src,
00174 sshort & sx,
00175 sshort & sy,
00176 sshort & x,
00177 sshort & y,
00178 sshort & w,
00179 sshort & h
00180 )
00181 {
00182 if (sx<0 || sy<0 || w<=0 || h<=0)
00183 return false;
00184
00185 if (w>=src->get_width()) w = src->get_width();
00186 if (h>=src->get_height()) h = src->get_height();
00187
00188 if (x>width) return false;
00189 if (y>height) return false;
00190
00191 if (x<0)
00192 {
00193 sx -= x;
00194 w += x;
00195 x = 0;
00196 }
00197 if (y<0)
00198 {
00199 sy -= y;
00200 h += y;
00201 y = 0;
00202 }
00203
00204 if (x+w>=width) { w -= x+w-width; }
00205 if (y+h>=height) { h -= y+h-height; }
00206
00207 if (sx<0 || sy<0 || w<=0 || h<=0)
00208 return false;
00209
00210 return true;
00211 }
00212
00213 void
00214 image_c::blt
00215 (
00216 image_c * src,
00217 sshort sx,
00218 sshort sy,
00219 sshort x,
00220 sshort y,
00221 sshort w,
00222 sshort h
00223 )
00224 {
00225 AssertThis;
00226
00227 AssertReturn3(src, buf, src->get_pixels());
00228 if (!prepare_blt(src, sy, sy, x, y, w, h))
00229 return;
00230
00231 ulong sp, dp;
00232 ushort v;
00233
00234 const char *srcbuf = src->get_pixels();
00235
00236 v = sy;
00237 for (ushort yy=y; yy<y+h; yy++)
00238 {
00239 sp = sx+v*src->width;
00240 dp = x +yy*width;
00241
00242 if (dp*4+3>buflen || sp*4+3>src->get_buffer_len())
00243 break;
00244
00245 memcpy(buf+dp*4, srcbuf+sp*4, 4*w);
00246 v++;
00247 }
00248 dirty = true;
00249 }
00250
00251 void
00252 image_c::blt_blend
00253 (
00254 image_c * src,
00255 sshort sx,
00256 sshort sy,
00257 sshort x,
00258 sshort y,
00259 sshort w,
00260 sshort h,
00261 sshort blendtype
00262 )
00263 {
00264 AssertThis;
00265
00266 if (blendtype==BT_OPAQUE)
00267 {
00268 blt(src, sx, sy, x, y, w, h);
00269 return;
00270 }
00271
00272 if (blendtype==BT_NONE)
00273 return;
00274
00275 AssertReturn3(src, buf, src->get_pixels());
00276 if (!prepare_blt(src, sy, sy, x, y, w, h))
00277 return;
00278
00279 const char *srcbuf = src->get_pixels();
00280 uchar r1,g1,b1,a1;
00281 uchar r2,g2,b2,a2;
00282
00283 ulong sp, dp;
00284 ulong u, v;
00285
00286 u = sx;
00287 for (sshort xx=x; xx<x+w; xx++)
00288 {
00289 v = sy;
00290 for (sshort yy=y; yy<y+h; yy++)
00291 {
00292 sp = u+v*src->width;
00293 dp = xx+yy*width;
00294
00295 AssertReturn2(dp*4+3<=buflen, sp*4+3<=src->get_buffer_len());
00296
00297 a1 = (uchar)buf[dp*4+3];
00298 a2 = (uchar)srcbuf[sp*4+3];
00299
00300 float alpha = a2/(float)255;
00301
00302 r1 = buf[dp*4+0];
00303 g1 = buf[dp*4+1];
00304 b1 = buf[dp*4+2];
00305
00306 r2 = srcbuf[sp*4+0];
00307 g2 = srcbuf[sp*4+1];
00308 b2 = srcbuf[sp*4+2];
00309
00310 switch (blendtype)
00311 {
00312 case BT_ALPHATEST:
00313 if (a2>0.5)
00314 {
00315 buf[dp*4+0] = (char)(r1*(1-alpha)+r2*alpha);
00316 buf[dp*4+1] = (char)(g1*(1-alpha)+g2*alpha);
00317 buf[dp*4+2] = (char)(b1*(1-alpha)+b2*alpha);
00318 buf[dp*4+3] = a2;
00319 }
00320 break;
00321
00322 case BT_ADD:
00323 buf[dp*4+0] += r2;
00324 buf[dp*4+1] += g2;
00325 buf[dp*4+2] += b2;
00326 buf[dp*4+3] += a2;
00327 break;
00328
00329 case BT_MODULATE:
00330 buf[dp*4+0] = (char)(((float)r2/255.0f+(float)r1/255.0f)*255);
00331 buf[dp*4+1] = (char)(((float)g2/255.0f+(float)g1/255.0f)*255);
00332 buf[dp*4+2] = (char)(((float)b2/255.0f+(float)b1/255.0f)*255);
00333 buf[dp*4+3] = (char)(((float)a2/255.0f+(float)a1/255.0f)*255);
00334 break;
00335
00336 case BT_BLEND:
00337 buf[dp*4+0] = (char)(r1*(1-alpha)+r2*alpha);
00338 buf[dp*4+1] = (char)(g1*(1-alpha)+g2*alpha);
00339 buf[dp*4+2] = (char)(b1*(1-alpha)+b2*alpha);
00340 if (a1<a2)
00341 buf[dp*4+3] = a2;
00342 break;
00343
00344 }
00345
00346 v++;
00347 }
00348
00349 u++;
00350 }
00351 dirty = true;
00352 }
00353
00354 void
00355 image_c::color_blend
00356 (
00357 image_c * src,
00358 sshort sx,
00359 sshort sy,
00360 sshort x,
00361 sshort y,
00362 sshort w,
00363 sshort h,
00364 color_t color
00365 )
00366 {
00367 AssertThis;
00368
00369 AssertReturn3(src, buf, src->get_pixels());
00370 if (!prepare_blt(src, sy, sy, x, y, w, h))
00371 return;
00372
00373 const char *srcbuf = src->get_pixels();
00374
00375
00376 uchar r1,g1,b1,a1;
00377 uchar r2,g2,b2,a2;
00378
00379 ulong sp, dp;
00380 sshort u,v;
00381
00382 u = sx;
00383 for (sshort xx=0; xx<w; xx++)
00384 {
00385 AssertReturn2(u<src->get_width(), xx+x<width);
00386
00387 v = sy;
00388 for (sshort yy=0; yy<h; yy++)
00389 {
00390 AssertReturn2(v<src->get_height(), yy+y<height);
00391
00392 sp = u+v*src->width;
00393 dp = (xx+x)+(y+yy)*width;
00394
00395 AssertReturn2(dp*4+3<=buflen, sp*4+3<=src->get_buffer_len());
00396
00397 a1 = (uchar)buf[dp*4+3];
00398 a2 = (uchar)srcbuf[sp*4+3];
00399
00400 float alpha = a2/(float)255;
00401
00402 r1 = buf[dp*4+0];
00403 g1 = buf[dp*4+1];
00404 b1 = buf[dp*4+2];
00405
00406 r2 = (uchar)(color&0xFF);
00407 g2 = (uchar)((color>>8)&0xFF);
00408 b2 = (uchar)((color>>16)&0xFF);
00409
00410 buf[dp*4+0] = (uchar)(r1*(1-alpha)+r2*alpha);
00411 buf[dp*4+1] = (uchar)(g1*(1-alpha)+g2*alpha);
00412 buf[dp*4+2] = (uchar)(b1*(1-alpha)+b2*alpha);
00413
00414 sshort na = a1+a2;
00415
00416 if (na>255) na = 255;
00417
00418 buf[dp*4+3] = (uchar)na;
00419
00420 v++;
00421 }
00422
00423 u++;
00424 }
00425 dirty = true;
00426 }
00427
00428 void
00429 image_c::copy
00430 (
00431 image_c * src
00432 )
00433 {
00434 AssertThis;
00435
00436 AssertReturn2(src, src->get_pixels());
00437
00438 SafeDelete(buf);
00439
00440 buf = new char[src->get_buffer_len()];
00441
00442 AssertReturn1(buf);
00443
00444 const char *srcbuf = src->get_pixels();
00445
00446 memcpy(buf, srcbuf, src->get_buffer_len());
00447 buflen = src->buflen;
00448 bpp = src->bpp;
00449 width = src->width;
00450 height = src->height;
00451 hasalpha = src->hasalpha;
00452 dirty = true;
00453 }
00454
00455 void
00456 image_c::crop
00457 (
00458 sshort x,
00459 sshort y,
00460 sshort w,
00461 sshort h
00462 )
00463 {
00464 AssertThis;
00465
00466 AssertReturn2(w>0, h>0);
00467
00468 x = x % width;
00469 y = y % height;
00470
00471 char *buf2 = new char[w*h*4*2];
00472
00473 AssertReturn1(buf2);
00474
00475 for (sshort xx=0; xx<w; xx++)
00476 {
00477 for (sshort yy=0; yy<h; yy++)
00478 {
00479 sshort srcx = xx+x;
00480 sshort srcy = yy+y;
00481
00482 srcx %= width;
00483 srcy %= height;
00484
00485 memcpy(&buf2[(xx+yy*w)*4], &buf[(srcx+srcy*width)*4], 4);
00486 }
00487 }
00488
00489 SafeArrayDelete(buf);
00490 buf = buf2;
00491 buflen = w*h*4;
00492 width = w;
00493 height = h;
00494 dirty = true;
00495 }
00496
00497 void image_c::draw
00498 (
00499 ushort x,
00500 ushort y
00501 )
00502 {
00503 AssertThis;
00504
00505 if (dirty)
00506 update_tex();
00507
00508 if (tex==INVALID_INDEX)
00509 {
00510 const char *srcbuf = get_pixels();
00511 AssertReturn1(srcbuf);
00512
00513 glRasterPos2s(x,gv.init.vres-y-1);
00514
00515 glViewport(x,gv.init.vres-y,width,height);
00516
00517 gv.renderer->set_blending(BT_BLEND);
00518
00519 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00520 glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, srcbuf);
00521
00522 glViewport(0,0,gv.init.hres, gv.init.vres);
00523 }
00524 else
00525 {
00526 gv.renderer->set_texture_params(TF_NEAREST, TF_NEAREST, TW_CLAMP, TW_CLAMP);
00527 gv.renderer->draw_pic(x,gv.init.vres-y-height, x+width, gv.init.vres-y, 0,0,1,1,tex,BT_BLEND);
00528 }
00529 }
00530
00531 void
00532 image_c::vline
00533 (
00534 sshort x,
00535 sshort y,
00536 sshort h,
00537 color_t color
00538 )
00539 {
00540 AssertThis;
00541
00542 AssertReturn1(buf);
00543
00544 if (x<0 || x>=width) { return; };
00545
00546 if (h+y>=height) h = height-y-1;
00547 if (y<0) { h+=y; y=0; };
00548
00549 char *startpos = buf+(x+y*width)*4;
00550 char col[4] = {
00551 (char)((color>>0)&0xFF),
00552 (char)((color>>8)&0xFF),
00553 (char)((color>>16)&0xFF),
00554 (char)((color>>24)&0xFF) };
00555
00556 for (sshort i=0; i<h; i++)
00557 memcpy(startpos+i*4*width, col, 4);
00558 dirty = true;
00559 }
00560
00561 void
00562 image_c::hline
00563 (
00564 sshort x,
00565 sshort y,
00566 sshort w,
00567 color_t color
00568 )
00569 {
00570 AssertThis;
00571
00572 AssertReturn1(buf);
00573
00574 if (w+x>=width) w = width-x;
00575 if (x<0) { w+=x; x=0; };
00576 if (y<0||y>=height) { return; };
00577
00578 char *startpos = buf+(x+y*width)*4;
00579 char col[4] = {
00580 (char)((color>>0)&0xFF),
00581 (char)((color>>8)&0xFF),
00582 (char)((color>>16)&0xFF),
00583 (char)((color>>24)&0xFF) };
00584
00585 for (sshort i=0; i<w; i++)
00586 memcpy(startpos+i*4, col, 4);
00587 dirty = true;
00588 }
00589
00590 void
00591 image_c::line
00592 (
00593 sshort x,
00594 sshort y,
00595 sshort w,
00596 sshort h,
00597 color_t color
00598 )
00599 {
00600 AssertThis;
00601
00602 sshort Ax = x, Ay = y, Bx = x+w, By = y+h;
00603
00604
00605
00606
00607 sshort dX = abs(Bx-Ax);
00608 sshort dY = abs(By-Ay);
00609
00610
00611
00612
00613 sshort Xincr, Yincr;
00614 if (Ax > Bx) { Xincr=-1; } else { Xincr=1; }
00615 if (Ay > By) { Yincr=-1; } else { Yincr=1; }
00616
00617
00618
00619
00620
00621
00622 if (dX >= dY)
00623 {
00624 sshort dPr = dY<<1;
00625 sshort dPru = dPr - (dX<<1);
00626 sshort P = dPr - dX;
00627
00628 for (; dX>=0; dX--)
00629 {
00630 set_pixel(Ax, Ay, color);
00631 if (P > 0)
00632 {
00633 Ax+=Xincr;
00634 Ay+=Yincr;
00635 P+=dPru;
00636 }
00637 else
00638 {
00639 Ax+=Xincr;
00640 P+=dPr;
00641 }
00642 }
00643 }
00644 else
00645 {
00646 sshort dPr = dX<<1;
00647 sshort dPru = dPr - (dY<<1);
00648 sshort P = dPr - dY;
00649
00650 for (; dY>=0; dY--)
00651 {
00652 set_pixel(Ax, Ay, color);
00653 if (P > 0)
00654 {
00655 Ax+=Xincr;
00656 Ay+=Yincr;
00657 P+=dPru;
00658 }
00659 else
00660 {
00661 Ay+=Yincr;
00662 P+=dPr;
00663 }
00664 }
00665 }
00666 dirty = true;
00667 }
00668
00669 void
00670 image_c::rectangle
00671 (
00672 sshort x,
00673 sshort y,
00674 sshort w,
00675 sshort h,
00676 color_t color
00677 )
00678 {
00679 AssertThis;
00680
00681 AssertReturn1(buf);
00682
00683 hline(x, y, w,color);
00684 hline(x, y+h-1, w,color);
00685 vline(x, y, h,color);
00686 vline(x+w-1, y, h,color);
00687 dirty = true;
00688 }
00689
00690 void
00691 image_c::filled_rectangle
00692 (
00693 sshort x,
00694 sshort y,
00695 sshort w,
00696 sshort h,
00697 color_t color
00698 )
00699 {
00700 AssertThis;
00701
00702 AssertReturn1(buf);
00703
00704 for (sshort i=0; i<h; i++)
00705 hline(x,y+i,w, color);
00706 dirty = true;
00707 }
00708
00709 sshort
00710 image_c::draw_char
00711 (
00712 sshort x,
00713 sshort y,
00714 uchar c,
00715 struct font_s * fnt,
00716 color_t color
00717 )
00718 {
00719 AssertThisV;
00720
00721 AssertReturnValue1(fnt, 0);
00722
00723 sshort w = fnt->widths[c];
00724
00725 color_blend(fnt->images[c], 0, 0, x, y, fnt->width, fnt->height, color);
00726
00727 dirty = true;
00728 return w;
00729 }
00730
00731 sshort
00732 image_c::draw_string
00733 (
00734 sshort x,
00735 sshort y,
00736 const char * c,
00737 struct font_s * fnt,
00738 color_t color
00739 )
00740 {
00741 AssertThisV;
00742
00743 AssertReturnValue2(c,fnt,0);
00744
00745 sshort w = 0;
00746
00747 for (ulong i=0; i<strlen(c); i++)
00748 w+=draw_char(x+w,y,c[i],fnt, color);
00749
00750 dirty = true;
00751 return w;
00752 }
00753
00755
00756 animation_c::animation_c()
00757 {
00758 img = new image_c;
00759 frame = 0;
00760 fps = 0;
00761 framecount = 0;
00762 }
00763
00764 animation_c::~animation_c()
00765 {
00766 AssertThis;
00767
00768 SafeDelete(img);
00769 }
00770
00771 bool
00772 animation_c::load
00773 (
00774 char * filename
00775 )
00776 {
00777 AssertThisV;
00778
00779 AssertReturnValue1(filename, false);
00780
00781 img->load(filename);
00782 set_framecount(1);
00783 set_frame(0);
00784 set_fps(0);
00785
00786 return true;
00787 }
00788
00789 void
00790 animation_c::set_framecount
00791 (
00792 ushort f
00793 )
00794 {
00795 AssertThis;
00796
00797 AssertReturn3(f, img, f<img->get_width());
00798
00799 image_c::create(img->get_width()/f,img->get_height());
00800
00801 framecount = f;
00802 }
00803
00804 void
00805 animation_c::set_fps
00806 (
00807 ushort f
00808 )
00809 {
00810 AssertThis;
00811
00812 fps = f;
00813 }
00814
00815 image_c *
00816 animation_c::set_frame
00817 (
00818 ushort f
00819 )
00820 {
00821 AssertThisV;
00822
00823 frame = f;
00824 blt(img, (img->get_width()*f/framecount), 0, 0, 0, width, height);
00825 return this;
00826 }
00827
00828 void
00829 animation_c::play
00830 (
00831 sshort type
00832 )
00833 {
00834 AssertThis;
00835
00836 playtype = type;
00837
00838 set_frame(0);
00839 playdir = 1;
00840
00841 if (fps)
00842 nextframetime = _time_get()+1000/fps;
00843 }
00844
00845 const char *
00846 animation_c::get_pixels
00847 ()
00848 {
00849 AssertThisV;
00850
00851 if (_time_get()>=nextframetime)
00852 {
00853 frame+=playdir;
00854
00855 if (frame>=framecount)
00856 {
00857 if (playtype == ANIM_PINGPONG)
00858 {
00859 playdir = -1;
00860 frame = framecount-1;
00861 }
00862 else if (playtype == ANIM_LOOP)
00863 {
00864 frame = 0;
00865 }
00866 else
00867 {
00868 playtype = 0;
00869 playdir = 0;
00870 frame = 0;
00871 }
00872 } else
00873 {
00874 if (frame<0)
00875 {
00876 if (playtype == ANIM_PINGPONG)
00877 {
00878 playdir = 0;
00879 frame = 0;
00880 }
00881 }
00882 }
00883
00884 if (playdir)
00885 nextframetime = _time_get()+1000/fps;
00886 }
00887
00888 set_frame(frame);
00889 dirty = true;
00890
00891 return image_c::get_pixels();
00892 }
00893
00894 void
00895 image_c::rgb2yuv
00896 ()
00897 {
00898 AssertThis;
00899
00900 AssertReturn1(buf);
00901
00902 for (ulong x=0; x<width; x++)
00903 for (ulong y=0; y<height; y++)
00904 {
00905 float r,g,b, yy,u,v;
00906
00907 r = buf[(x+y*width)*4+0];
00908 g = buf[(x+y*width)*4+1];
00909 b = buf[(x+y*width)*4+2];
00910
00911 yy = 0.299f*r + 0.587f*g + 0.114f*b;
00912 u = (b-yy)*0.565f;
00913 v = (r-yy)*0.713f;
00914
00915 buf[(x+y*width)*4+0]=(char)y;
00916 buf[(x+y*width)*4+1]=(char)u;
00917 buf[(x+y*width)*4+2]=(char)v;
00918 }
00919
00920 dirty = true;
00921 }
00922
00923 void
00924 image_c::yuv2rgb
00925 ()
00926 {
00927 AssertThis;
00928
00929 AssertReturn1(buf);
00930
00931 for (ulong x=0; x<width; x++)
00932 for (ulong y=0; y<height; y++)
00933 {
00934 float r,g,b, yy,u,v;
00935
00936 yy = buf[(x+y*width)*4+0];
00937 u = buf[(x+y*width)*4+1];
00938 v = buf[(x+y*width)*4+2];
00939
00940 r = yy + 1.403f;
00941 g = yy - 0.344f*u - 0.714f*v;
00942 b = yy + 1.770f*u;
00943
00944 buf[(x+y*width)*4+0]=(char)r;
00945 buf[(x+y*width)*4+1]=(char)g;
00946 buf[(x+y*width)*4+2]=(char)b;
00947 }
00948 dirty = true;
00949 }
00950
00951
00952
00953 void
00954 image_c::set_pixel
00955 (
00956 sshort x,
00957 sshort y,
00958 color_t color
00959 )
00960 {
00961 AssertThis;
00962
00963 AssertReturn1(buf);
00964 AssertReturn4(x>=0, x<width, y>=0, y<height);
00965
00966 char col[4] = {
00967 (char)((color>>0)&0xFF),
00968 (char)((color>>8)&0xFF),
00969 (char)((color>>16)&0xFF),
00970 (char)((color>>24)&0xFF) };
00971
00972 memcpy(buf+(x+y*width)*4, col, 4);
00973
00974 dirty = true;
00975 }
00976
00977
00978 void image_c::update_tex()
00979 {
00980 if (!dirty)
00981 return;
00982
00983 if (tex == INVALID_INDEX)
00984 tex = gv.texman->create(width, height, "*pic");
00985
00986 gv.texman->set_image(tex, this, true, true);
00987 dirty = false;
00988 }