001 #ifndef ENGINE_2D 002 #define ENGINE_2D 003 #include "Primtives3D.HC"; 004 //2 dimensional object 005 extern class C2DWorld; 006 class C2DObject:CQue { 007 U64 ident; 008 //See replace_color/with_color 009 #define C2DOBJF_REPLACE_COLOR 1 010 #define C2DOBJF_MESH 2 011 I64 flags; 012 union { 013 CDC *graphics; 014 U8 *sprite; 015 CD6 *mesh; 016 }; 017 F64 x,y,z; 018 F64 center_x,center_y; 019 F64 center_z; 020 F64 rot; 021 F64 rotx,roty; 022 F64 scale; 023 F64 priority; 024 F64 width,height; 025 //This matrix includes all transofrmations 026 U64 mat[16]; 027 Bool flipped; 028 Bool is_sprite; 029 Bool is_cd6_mesh; 030 U8 replace_color; 031 union { 032 U8 with_color; 033 U8 color; 034 } 035 U8 pad[4]; 036 CTask *mem_task; 037 I64 user_data,lock; 038 U8 name[STR_LEN]; 039 //Private 040 I64 _blot_at_x,_blot_at_y; 041 CDC *_blot_dc; 042 C2DWorld *world; 043 }; 044 CTask *mem_task=Fs; 045 class C2DWorld { 046 I64 background_color; 047 CDC *scrn; 048 CQue objects; 049 I64 in_draw; 050 }; 051 C2DWorld *C2DWorldNew(I64 background_color=BLACK) { 052 C2DWorld *ret=GCCAlloc(sizeof C2DWorld); 053 QueInit(&ret->objects); 054 CDC *scrn; 055 ret->scrn=scrn=DCNew(GR_WIDTH,GR_HEIGHT); 056 scrn->transform=&WorldTransform; 057 scrn->x=scrn->width>>1; 058 scrn->y=scrn->height>>1; 059 scrn->z=-1; 060 Mat4x4IdentEqu(ret->scrn->r); 061 ret->background_color=background_color; 062 DCDepthBufAlloc(ret->scrn); 063 return ret; 064 } 065 U0 C2DObjectUpdateMat(C2DObject *obj) { 066 //This sets us to the identity matrix 067 Mat4x4IdentEqu(obj->mat); 068 069 //1: move center of graphics to (0,0) 070 //2: rotate 071 //3: scale 072 //4: move to (x,y) 073 074 // 075 // Move center to 0,0 076 // Becasue rotations are rotated around (0,0) 077 // 078 Mat4x4TranslationAdd(obj->mat, 079 -obj->center_x, //Use negative cordnates to move towards 0,0 080 -obj->center_y, 081 -obj->center_z); 082 // 083 //Flip the image by rotationg around the Y axis 084 // 085 if(obj->flipped) 086 Mat4x4RotY(obj->mat,pi); 087 // 088 // We need to rotate around the center 089 // 090 Mat4x4RotX(obj->mat,obj->rotx); 091 Mat4x4RotY(obj->mat,obj->roty); 092 Mat4x4RotZ(obj->mat,obj->rot); 093 // 094 // Scale the image 095 // 096 Mat4x4Scale(obj->mat,obj->scale); 097 // 098 // Now we move 099 // 100 Mat4x4TranslationAdd(obj->mat,obj->x,obj->y,obj->z); 101 } 102 U0 C2DObjectFinalize(C2DObject *obj) { 103 if(!obj->is_sprite&&!obj->is_cd6_mesh) 104 DCDel(obj->graphics); 105 else if(obj->is_sprite) 106 Free(obj->sprite); 107 } 108 C2DObject *C2DObjectNewFromSprite(U8 *sprite) { 109 I64 min_x,max_x,min_y,max_y; 110 C2DObject *new=GCCAlloc(sizeof(C2DObject)); 111 GCFinalize(new,&C2DObjectFinalize); 112 new->ident='Obj'; 113 new->mem_task=mem_task; 114 SpriteExtents(sprite,&min_x,&max_x,&min_y,&max_y); 115 new->width=max_x-min_x; 116 new->height=max_y-min_y; 117 new->sprite=CAlloc(SpriteSize(sprite),mem_task); 118 MemCpy(new->sprite,sprite,SpriteSize(sprite)); 119 new->is_sprite=TRUE; 120 Mat4x4IdentEqu(new->mat); 121 new->scale=1; 122 QueInit(new); 123 return new; 124 } 125 126 127 U0 C2DObjectSetGraphicsFromSprite(C2DObject *obj,U8 *sprite) { 128 I64 min_x,max_x,min_y,max_y; 129 if(!obj->is_sprite&&!obj->is_cd6_mesh) 130 DCDel(obj->graphics); 131 else if(obj->sprite) 132 Free(obj->sprite); 133 obj->sprite=CAlloc(SpriteSize(sprite),obj->mem_task); 134 MemCpy(obj->sprite,sprite,SpriteSize(sprite)); 135 sprite=obj->sprite; 136 SpriteExtents(sprite,&min_x,&max_x,&min_y,&max_y); 137 obj->width=max_x-min_x; 138 obj->center_x=0; 139 obj->center_y=0; 140 obj->sprite=sprite; 141 obj->is_sprite=TRUE; 142 C2DObjectUpdateMat(obj); 143 } 144 145 U0 C2DObjectSetMesh(C2DObject *obj,CD6 *mesh) { 146 if(!obj->is_sprite&&!obj->is_cd6_mesh) 147 DCDel(obj->graphics); 148 else if(obj->sprite) 149 Free(obj->sprite); 150 obj->is_cd6_mesh=TRUE; 151 obj->mesh=mesh; 152 obj->center_x=0; 153 obj->center_y=0; 154 obj->width=CD6Width(mesh); 155 obj->height=CD6Height(mesh); 156 C2DObjectUpdateMat(obj); 157 } 158 C2DObject *C2DObjectNewFromMesh(CD6 *mesh) { 159 C2DObject *new=GCCAlloc(sizeof C2DObject); 160 GCFinalize(new,&C2DObjectFinalize); 161 new->ident='Obj'; 162 new->color=WHITE; 163 new->mem_task=mem_task; 164 Mat4x4IdentEqu(new->mat); 165 new->scale=1; 166 QueInit(new); 167 C2DObjectSetMesh(new,mesh); 168 return new; 169 } 170 171 C2DObject *C2DObjectNewFromDC(CDC *img) { 172 C2DObject *new=GCCAlloc(sizeof C2DObject); 173 GCFinalize(new,&C2DObjectFinalize); 174 new->ident='Obj'; 175 new->mem_task=mem_task; 176 new->graphics=DCCopy(img,mem_task); 177 new->center_x=img->width/2 ; 178 new->center_y=img->height/2; 179 new->width=img->width; 180 new->height=img->height; 181 Mat4x4IdentEqu(new->mat); 182 new->scale=1; 183 QueInit(new); 184 return new; 185 } 186 U0 C2DObjectMoveCenter(C2DObject *obj,F64 x,F64 y,F64 z=0) { 187 obj->center_x=x,obj->center_y=y; 188 obj->center_z=z; 189 C2DObjectUpdateMat(obj); 190 } 191 U0 C2DObjectMove(C2DObject *obj,F64 x,F64 y,F64 z=0) { 192 obj->x=x,obj->y=y,obj->z=z; 193 C2DObjectUpdateMat(obj); 194 } 195 U0 C2DObjectRotate(C2DObject *obj,F64 rot=0) { 196 obj->rot=rot; 197 C2DObjectUpdateMat(obj); 198 } 199 U0 C2DObjectScale(C2DObject *obj,F64 s) { 200 obj->scale=s; 201 C2DObjectUpdateMat(obj); 202 } 203 U0 C2DObjectSetGraphics(C2DObject *obj,CDC *gr) { 204 if(!obj->is_sprite&&!obj->is_cd6_mesh) 205 DCDel(obj->graphics); 206 else if(obj->sprite) 207 Free(obj->sprite); 208 obj->graphics=DCCopy(gr,obj->mem_task); 209 obj->center_x=gr->width/2 ; 210 obj->center_y=gr->height/2; 211 obj->width=gr->width; 212 obj->height=gr->height; 213 C2DObjectUpdateMat(obj); 214 } 215 216 U0 PrepareForBlot(C2DObject *obj) { 217 I64 dummy,min_x,min_y,max_x,max_y; 218 CDC *sprite_dc; 219 CD2I64 a,b,c,d; 220 C2DObjectUpdateMat(obj); 221 if(!obj->is_sprite) 222 ; //GrBlot3(to,0,0,depth_offset,obj->graphics); 223 else if(!(obj->flags&C2DOBJF_MESH)) { 224 SpriteExtents(obj->sprite,&a.x,&b.x,&a.y,&b.y); 225 c.x=a.x; 226 c.y=b.y; 227 d.x=b.x; 228 d.y=a.y; 229 Mat4x4MulXYZ(obj->mat,&a.x,&a.y,&dummy); 230 Mat4x4MulXYZ(obj->mat,&b.x,&b.y,&dummy); 231 Mat4x4MulXYZ(obj->mat,&c.x,&c.y,&dummy); 232 Mat4x4MulXYZ(obj->mat,&d.x,&d.y,&dummy); 233 min_x=MinI64(a.x,b.x); 234 min_x=MinI64(min_x,c.x); 235 min_x=MinI64(min_x,d.x); 236 237 min_y=MinI64(a.y,b.y); 238 min_y=MinI64(min_y,c.y); 239 min_y=MinI64(min_y,d.y); 240 241 max_x=MaxI64(a.x,b.x); 242 max_x=MaxI64(max_x,c.x); 243 max_x=MaxI64(max_x,d.x); 244 245 max_y=MaxI64(a.y,b.y); 246 max_y=MaxI64(max_y,c.y); 247 max_y=MaxI64(max_y,d.y); 248 249 sprite_dc=DCNew( 250 Clamp(max_x-min_x+1,1,GR_WIDTH), 251 Clamp(max_y-min_y+1,1,GR_HEIGHT)); 252 DCFill(sprite_dc); 253 Sprite3Mat4x4B(sprite_dc,-min_x,-min_y,0,obj->sprite,obj->mat); 254 //Compute center 255 c.x=0,c.y=0; 256 Mat4x4MulXYZ(obj->mat,&c.x,&c.y,&dummy); 257 obj->_blot_at_x=c.x-(c.x-min_x); 258 obj->_blot_at_y=c.y-(c.y-min_y); 259 obj->_blot_dc=sprite_dc; 260 } 261 } 262 U0 C2DObjectRemoveFromWorld(C2DObject *obj) { 263 QueRem(obj); 264 QueInit(obj); 265 } 266 U0 C2DObjectDel(C2DObject *obj) { 267 QueRem(obj); 268 if(!obj->is_sprite&&!obj->is_cd6_mesh) 269 DCDel(obj->graphics); 270 GCFree(obj); 271 } 272 U0 C2DWorldDel(C2DWorld *world) { 273 C2DObject *cur,*next; 274 I64 idx; 275 while(LBts(&world->in_draw,0)) 276 Sleep(1); 277 for(cur=world->objects.next;cur!=&world->objects;) { 278 next=cur->next; 279 C2DObjectDel(cur); 280 cur=next; 281 } 282 GCFree(world);; 283 } 284 U0 AddObjectToWorld(C2DObject *obj,C2DWorld *world) { 285 while(LBts(&world->in_draw,0)) 286 Yield; 287 C2DObject *head=&world->objects,*cur=head->next; 288 if(!obj->priority) 289 obj->priority=QueCnt(head); 290 while(cur!=head) { 291 if(obj->priority<cur->priority) { 292 QueInsRev(obj,cur); 293 goto fin; 294 } 295 cur=cur->next; 296 } 297 obj->world=world; 298 QueIns(obj,head->last); 299 fin: 300 LBtr(&world->in_draw,0); 301 } 302 class CMPDrawItNugget { 303 CDC *to; 304 C2DWorld *world; 305 I64 start,end; 306 CMPDrawItNugget *last,*next; 307 I64 ready_to_merge; 308 I64 merged; 309 CTask *parent; 310 I64 done; 311 }; 312 U0 MPDrawIt(CMPDrawItNugget *nugget) { 313 C2DObject *head=&nugget->world->objects,*cur=head->next; 314 I64 old_flags; 315 U8 *old_mat; 316 if(!nugget->to) { 317 nugget->to=DCNew( 318 nugget->world->scrn->width, 319 nugget->world->scrn->height, 320 nugget->world->scrn->mem_task); 321 DCFill(nugget->to,TRANSPARENT); 322 nugget->to->flags|=nugget->world->scrn->flags&DCF_TRANSFORMATION; 323 Mat4x4Equ(nugget->to->r,nugget->world->scrn->r); 324 } 325 I64 i; 326 for(i=0;i<nugget->end&&cur!=head;i++) { 327 if(nugget->start<=i) { 328 PrepareForBlot(cur); 329 if(cur->flags&C2DOBJF_MESH) { 330 C2DObjectUpdateMat(cur); 331 Sprite3Mat4x4B(nugget->to,0,0,0,cur->sprite,cur->mat); 332 } else if(!cur->is_sprite) { 333 old_flags=nugget->to->flags; 334 old_mat=nugget->to->r; 335 nugget->to->flags|=DCF_TRANSFORMATION; 336 nugget->to->r=cur->mat; 337 if(cur->graphics) { 338 if(cur->flags&C2DOBJF_REPLACE_COLOR) 339 DCColorChg(cur->graphics,cur->replace_color,cur->with_color); 340 GrBlot3(nugget->to,0,0,0,cur->graphics); 341 } 342 nugget->to->r=old_mat; 343 nugget->to->flags=old_flags; 344 } else { 345 if(cur->flags&C2DOBJF_REPLACE_COLOR) 346 DCColorChg(cur->_blot_dc,cur->replace_color,cur->with_color); 347 GrBlot(nugget->to,cur->_blot_at_x,cur->_blot_at_y,cur->_blot_dc); 348 DCDel(cur->_blot_dc); 349 cur->_blot_dc=NULL; 350 } 351 } 352 cur=cur->next; 353 } 354 nugget->parent->wake_jiffy=0; 355 LBts(&nugget->done,0); 356 } 357 I64 PrioritySort(C2DObject *a,C2DObject *b) { 358 if(b->priority>a->priority) return 1; 359 if(b->priority<a->priority) return -1; 360 return 0; 361 } 362 U0 WorldSortByPriority(C2DWorld *w) { 363 I64 cnt=QueCnt(&w->objects),i; 364 C2DObject **sorted=GCCAlloc(8*cnt); 365 C2DObject *head=&w->objects,*cur=head->next; 366 for(cnt=0;cur!=head;cnt++) { 367 sorted[cnt]=cur; 368 cur=cur->next; 369 } 370 QSortI64(sorted,cnt,&PrioritySort); 371 QueInit(&w->objects); 372 for(i=0;i!=cnt;i++) { 373 QueIns(sorted[i],&w->objects); 374 } 375 GCFree(sorted); 376 } 377 U0 DrawWorld(CTask *t,C2DWorld *world) { 378 if(!t) t=Fs; 379 LBts(&world->in_draw,0); 380 I64 i,core_cnt,i2=0,cap; 381 I64 old_flags,*old_mat; 382 U8 *otrans; 383 CDC *scrn=world->scrn; 384 CMPDrawItNugget nuggets[mp_cnt]; 385 MemSet(nuggets,0,sizeof(CMPDrawItNugget)*mp_cnt); 386 scrn->color=world->background_color; 387 DCDepthBufRst(scrn); 388 DCFill(scrn,TRANSPARENT); 389 TextRect(t->win_left,t->win_right,t->win_top,t->win_bottom,world->background_color<<12); 390 //head points to the head of the CQue 391 C2DObject *head=&world->objects,*cur=head->next; 392 WorldSortByPriority(world); 393 //Because CQue's wrap around,we check for head as the last element 394 395 // A is the head 396 // 397 // A->B->C-\ 398 // ^ | 399 // | | 400 // \-------/ 401 // 402 one: 403 cur=head->next; 404 while(cur!=head) { 405 PrepareForBlot(cur); 406 cur=cur->next; 407 } 408 i2=QueCnt(head); 409 cur=head->next; 410 while(i2--) { 411 if(cur->is_cd6_mesh) { 412 scrn->thick=1; 413 scrn->color=cur->color; 414 otrans=scrn->transform; 415 old_flags=scrn->flags; 416 scrn->flags|=DCF_TRANSFORMATION; 417 CD6Draw(cur->mesh,0,0,0,scrn,cur->mat); 418 scrn->transform=otrans; 419 } else if(cur->flags&C2DOBJF_MESH) { 420 C2DObjectUpdateMat(cur); 421 Sprite3Mat4x4B(scrn,0,0,0,cur->sprite,cur->mat); 422 } else if(!cur->is_sprite) { 423 old_flags=scrn->flags; 424 old_mat=scrn->r; 425 scrn->flags|=DCF_TRANSFORMATION; 426 scrn->r=cur->mat; 427 if(cur->graphics) { 428 if(cur->flags&C2DOBJF_REPLACE_COLOR) 429 DCColorChg(cur->graphics,cur->replace_color,cur->with_color); 430 GrBlot3(scrn,0,0,cur->z,cur->graphics); 431 } 432 scrn->r=old_mat; 433 scrn->flags=old_flags; 434 } else { 435 if(cur->flags&C2DOBJF_REPLACE_COLOR) 436 DCColorChg(cur->_blot_dc,cur->replace_color,cur->with_color); 437 GrBlot3(scrn,cur->_blot_at_x,cur->_blot_at_y,cur->z,cur->_blot_dc); 438 DCDel(cur->_blot_dc); 439 } 440 cur=cur->next; 441 } 442 LBtr(&world->in_draw,0); 443 } 444 U0 C2DObjectPointTo(C2DObject *obj,F64 x,F64 y) { 445 //We want to make the x,y relative to the obj's cordnates 446 x-=obj->x; 447 y-=obj->y; 448 //https://en.wikipedia.org/wiki/Atan2 449 //ATan2 gets the angle that points to (x,y) 450 obj->rot=Arg(x,y); 451 C2DObjectUpdateMat(obj); 452 } 453 // 454 // Test section 455 // 456 class CD2F64 { 457 F64 x,y; 458 }; 459 U0 CrossProduct(CD2F64 *dst,CD2F64 *a,CD2F64 *b) { 460 dst->x=a->y-b->y; 461 dst->y=a->x-b->x; 462 } 463 Bool InRange(F64 a,F64 v,F64 b) { 464 if(a>b) 465 return a>=v>=b; 466 return a<=v<=b; 467 } 468 class CD2F64 { 469 F64 x,y; 470 }; 471 U0 CrossProduct(CD2F64 *dst,CD2F64 *a,CD2F64 *b) { 472 dst->x=a->y-b->y; 473 dst->y=a->x-b->x; 474 } 475 Bool InRange(F64 a,F64 v,F64 b) { 476 if(a>b) 477 return a>=v>=b; 478 return a<=v<=b; 479 } 480 Bool PlaneIntersect(CD2I64 *dst,CD2I64 *a,CD2I64 *b,CD2I64 *a2,CD2I64 *b2) { 481 /* 482 * Nroot here,Heres the deal,I make a system of 2 linear equations and solve for an intersect 483 * I solve for the intersect and check if they are in bounds of points 484 485 Check for intersection basically. 486 487 / 488 ----*------ 489 / 490 / 491 / 492 */ 493 F64 slope1,slope2,off1,off2; 494 CD2I64 dummy; 495 if(!dst) dst=&dummy; 496 //If the line points straight up,we can check to see if the other 497 //line goes through the y position,if so,it is a hit 498 if((b->x==a->x)||(b2->x==a2->x)) { 499 if(a->x==b->x&&a2->x==b2->x) { 500 if(a->x==a2->x) { 501 dst->x=a->x; 502 dst->y=a->y; 503 goto fin; 504 } else 505 return FALSE; 506 } 507 if(a->x==b->x) { 508 dst->x=a->x; 509 slope2=(ToF64(b2->y)-a2->y)/(ToF64(b2->x)-a2->x); 510 dst->y=slope2*(dst->x-a2->x)+a2->y; 511 goto fin; 512 } 513 if(a2->x==b2->x) { 514 dst->x=a2->x; 515 slope1=(ToF64(b->y)-a->y)/(ToF64(b->x)-a->x); 516 dst->y=slope1*(dst->x-a->x)+a->y; 517 goto fin; 518 } 519 goto fin; 520 } 521 //https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection 522 slope2=(ToF64(b2->y)-a2->y)/(ToF64(b2->x)-a2->x); 523 slope1=(ToF64(b->y)-a->y)/(ToF64(b->x)-a->x); 524 off1=slope1*-a->x+a->y; 525 off2=slope2*-a2->x+a2->y; 526 dst->x=((off2-off1)/(slope1-slope2)); 527 dst->y=slope1*(dst->x)+off1; 528 fin: 529 return InRange(a->x,dst->x,b->x)&& 530 InRange(a2->x,dst->x,b2->x)&& 531 InRange(a->y,dst->y,b->y)&& 532 InRange(a2->y,dst->y,b2->y); 533 } 534 Bool C2DObjectCollisionTest(C2DObject *o1,C2DObject *o2,CD2I64 *hit_at=NULL) { 535 I64 nul=1,i,i2; 536 I64 o1_mat[16],o2_mat[16]; 537 CD2I64 *o1_edges[5]; 538 CD2I64 *o2_edges[5]; 539 CD2I64 a,b,c,d; 540 CD2I64 a2,b2,c2,d2; 541 if(!o1->is_sprite) { 542 a.x=0; 543 b.x=0+o1->width; 544 c.x=0+o1->width; 545 d.x=0; 546 547 a.y=0; 548 b.y=0; 549 c.y=0+o1->height; 550 d.y=0+o1->height; 551 } else { 552 SpriteExtents(o1->sprite,&a.x,&b.x,&a.y,&c.y); 553 d.x=a.x; //min 554 c.x=b.x; //max 555 b.y=a.y; //min 556 d.y=c.y; //max 557 } 558 559 if(!o2->is_sprite) { 560 a2.x=0; 561 b2.x=0+o2->width; 562 c2.x=0+o2->width; 563 d2.x=0; 564 565 a2.y=0; 566 b2.y=0; 567 c2.y=0+o2->height; 568 d2.y=0+o2->height; 569 } else { 570 SpriteExtents(o2->sprite,&a2.x,&b2.x,&a2.y,&c2.y); 571 d2.x=a2.x; //min 572 c2.x=b2.x; //max 573 b2.y=a2.y; //min 574 d2.y=c2.y; //max 575 } 576 577 C2DObjectUpdateMat(o1); 578 C2DObjectUpdateMat(o2); 579 Mat4x4Equ(o1_mat,o1->mat); 580 Mat4x4Equ(o2_mat,o2->mat); 581 // Mat4x4Scale(o1_mat,1<<16); 582 // Mat4x4Scale(o2_mat,1<<16); 583 nul=0; 584 Mat4x4MulXYZ(o1_mat,&a.x,&a.y,&nul); 585 nul=0; 586 Mat4x4MulXYZ(o1_mat,&b.x,&b.y,&nul); 587 nul=0; 588 Mat4x4MulXYZ(o1_mat,&c.x,&c.y,&nul); 589 nul=0; 590 Mat4x4MulXYZ(o1_mat,&d.x,&d.y,&nul); 591 592 nul=0; 593 Mat4x4MulXYZ(o2_mat,&a2.x,&a2.y,&nul); 594 nul=0; 595 Mat4x4MulXYZ(o2_mat,&b2.x,&b2.y,&nul); 596 nul=0; 597 Mat4x4MulXYZ(o2_mat,&c2.x,&c2.y,&nul); 598 nul=0; 599 Mat4x4MulXYZ(o2_mat,&d2.x,&d2.y,&nul); 600 601 o1_edges[0]=&a; 602 o1_edges[1]=&b; 603 o1_edges[2]=&c; 604 o1_edges[3]=&d; 605 o1_edges[4]=&a; 606 607 o2_edges[0]=&a2; 608 o2_edges[1]=&b2; 609 o2_edges[2]=&c2; 610 o2_edges[3]=&d2; 611 o2_edges[4]=&a2; 612 613 for(i=0;i!=4;i++) 614 for(i2=0;i2!=4;i2++) { 615 if(PlaneIntersect(hit_at,o1_edges[i],o1_edges[i+1], 616 o2_edges[i2],o2_edges[i2+1])) { 617 if(hit_at) hit_at->x/=(1<<16); 618 if(hit_at) hit_at->y/=(1<<16); 619 return TRUE; 620 } 621 } 622 return FALSE; 623 } 624 U0 C2DObjectSetFlip(C2DObject *sp,Bool flip) { 625 sp->flipped=flip; 626 C2DObjectUpdateMat(sp); 627 } 628 C2DObject *C2DObjectCopy(C2DObject *src) { 629 C2DObject *copy=GCMAllocIdent(src); 630 Mat4x4Equ(copy->mat,src->mat); 631 copy->mem_task=mem_task; 632 if(copy->is_sprite) 633 copy->sprite=src->sprite; 634 else if(copy->is_cd6_mesh) 635 copy->mesh=src->mesh; 636 else 637 copy->graphics=DCCopy(src->graphics,mem_task); 638 return copy; 639 } 640 #endif