0001 #define mp_cnt 1 0002 #include "AnimDC.HC" 0003 #include "BlobFile.HC" 0004 #include "SmallTalk/Load.HC" 0005 #include "Intersect.HC" 0006 #include "QuestEditor.HC"; 0007 #include "PathFinder.HC"; 0008 #define TEST_3D 0009 #ifndef ENGINE_3D 0010 #include "SSE.HC"; 0011 #define VIEW_DIST 32 0012 #define FOG_DIVISIONS 0x10 0013 #define FOG_DIST (128*4.) 0014 U64 fog_table[COLORS_NUM][COLORS_NUM][FOG_DIVISIONS]; 0015 U0 ErectFogTable0(U64 *table,I64 fog_color,F64 ratio) { 0016 CBGR48 palette[COLORS_NUM]; 0017 I64 idx,which; 0018 F64 r,g,b,dist,best_dist; 0019 F64 r2,g2,b2; 0020 U16 best_color,dither; 0021 GrPaletteGet(palette); 0022 for(idx=0;idx!=COLORS_NUM;idx++) { 0023 r=palette[idx].r*ratio+palette[fog_color].r*(1.-ratio); 0024 g=palette[idx].g*ratio+palette[fog_color].g*(1.-ratio); 0025 b=palette[idx].b*ratio+palette[fog_color].b*(1.-ratio); 0026 best_dist=1e100; 0027 for(dither=0;dither!=0xff;dither++) { 0028 r2=(palette[dither&0xf].r+palette[dither>>4].r)/2.; 0029 g2=(palette[dither&0xf].g+palette[dither>>4].g)/2.; 0030 b2=(palette[dither&0xf].b+palette [dither>>4].b)/2.; 0031 dist=Sqrt(Sqr(r-r2)+Sqr(g-g2)+Sqr(b-b2)); 0032 if(dist<best_dist) { 0033 best_color=dither; 0034 best_dist=dist; 0035 } 0036 } 0037 table[idx].u8[0]=best_color&0xf; 0038 table[idx].u8[2]=best_color&0xf; 0039 table[idx].u8[4]=best_color&0xf; 0040 table[idx].u8[6]=best_color&0xf; 0041 0042 table[idx].u8[1]=best_color>>4; 0043 table[idx].u8[3]=best_color>>4; 0044 table[idx].u8[5]=best_color>>4; 0045 table[idx].u8[7]=best_color>>4; 0046 } 0047 } 0048 U0 ErectFogTable(U64 *table,I64 divisions) { 0049 I64 f,d; 0050 for(d=0;d!=divisions;d++) { 0051 for(f=0;f!=16;f++) 0052 ErectFogTable0(&table[f*COLORS_NUM+d*COLORS_NUM*FOG_DIVISIONS],f,d/ToF64(divisions)); 0053 } 0054 } 0055 ErectFogTable(fog_table,0x10); 0056 U0 FrogImgBlank(CFrogImg *img) { 0057 img->dc=DCNew(1,1,frog_mem_task); 0058 img->name=FrogStrNew(""); 0059 } 0060 U0 FrogImgSetGraphics(CFrogImg *img,I64 *argv,I64 argc) { 0061 U8 *lunk=AsString(argv[0]),*data,*symbol_name; 0062 if(img->dc) 0063 AnimDCDel(img->dc); 0064 img->dc=AnimDCNew(1,1,frog_mem_task); 0065 if(lunk) { 0066 if(data=BlobFileGetLump(,lunk)) { 0067 AnimDCDel(img->dc); 0068 img->dc=AnimDCLoad(data,,frog_mem_task); 0069 img->name=FrogStrNew(lunk); 0070 Free(data); 0071 } 0072 Free(lunk); 0073 } 0074 return FROG_SMALL_NIL; 0075 } 0076 AddMethod("CFrogImg","setGraphics:",&FrogImgSetGraphics); 0077 CFrogNum *FrogImgWidth(CFrogImg *img,I64 *argv,I64 argc) { 0078 if(img->dc) 0079 return FrogNumNew(img->dc->width); 0080 return FROG_SMALL_NIL; 0081 } 0082 AddMethod("CFrogImg","width",&FrogImgWidth); 0083 CFrogNum *FrogImgHeight(CFrogImg *img,I64 *argv,I64 argc) { 0084 if(img->dc) 0085 return FrogNumNew(img->dc->height); 0086 return FROG_SMALL_NIL; 0087 } 0088 AddMethod("CFrogImg","height",&FrogImgHeight); 0089 #include "TextureEditor"; 0090 CFrogImg *FrogImgNewFromEditor(CFrogImg *img,I64 *argv,I64 argc) { 0091 U8 *lump; 0092 lump=TextureEdit(dft_blob_path); 0093 CFrogImg *ret=FROG_SMALL_NIL; 0094 if(lump) { 0095 ret=CallScript("get:",img,FrogStrNew(lump)); //Get an existing name/replace 0096 CallScript("setGraphics:",ret,FrogStrNew(lump)); 0097 Free(lump); 0098 } 0099 return ret; 0100 } 0101 AddClassMethod("CFrogImg","newFromEditor",&FrogImgNewFromEditor); 0102 U0 FrogImgDel(CFrogImg *img) { 0103 AnimDCDel(img->dc); 0104 Free(img); 0105 } 0106 0107 CFrogStr *FrogImgToString(CFrogImg *img,I64 *argv,I64 argc) { 0108 CFrogStr *s=ConstructThing("CFrogStr"); 0109 I64 len; 0110 U8 *a=AnimDCSave(img->dc,&len); 0111 U8SetAddBytes(s->items,a,len); 0112 Free(a); 0113 return s; 0114 } 0115 AddMethod("CFrogImg","asString",&FrogImgToString); 0116 CFrogStr *FrogImgFromString(CFrogImg *img,I64 *argv,I64 argc) { 0117 CFrogStr *s=argv[0]; 0118 CDC *d=NULL; 0119 if(s) { 0120 d=AnimDCLoad(s->items->body,,frog_mem_task); 0121 AnimDCDel(img->dc); 0122 img->dc=d; 0123 } 0124 return FROG_SMALL_NIL; 0125 } 0126 AddMethod("CFrogImg","setGraphicsFromString:",&FrogImgFromString); 0127 0128 0129 U64 Fog(I64 color,U64 dist,U8 fcolor=BLACK) { 0130 dist/=FOG_DIST; 0131 if(dist<FOG_DIVISIONS) { 0132 return fog_table[dist][color][fcolor]; 0133 } 0134 return fcolor; 0135 } 0136 Bool IsLiquidTile(I64 t) { 0137 switch(t) { 0138 case 6: //water 0139 case 10: //lava 0140 return TRUE; 0141 } 0142 return FALSE; 0143 } 0144 extern I64 *GetTilesInPath(U8 *w,F64 angle,F64 dist); 0145 #define ENGINE_3D 1 0146 #define SCRN_TURN_MARGIN 100 0147 #define SCRN_TURN_RATE (pi/30./7) 0148 //This will delegate calls to other cores 0149 class CCSPair { 0150 U8 *name; 0151 CFrogThing *thing; 0152 CHashTable *ht; 0153 }; 0154 // 0155 // From LevelEditor.HC 0156 // 0157 class CFilePtrLen { 0158 I32 ptr; 0159 I32 len; 0160 }; 0161 class CFileTexture { 0162 I64 idx; 0163 U8 blob_name[STR_LEN]; 0164 U8 wall_blob_name[STR_LEN]; 0165 U8 ceil_blob_name[STR_LEN]; 0166 }; 0167 0168 class CFileThingTemplate { 0169 I16 idx; 0170 U8 name[STR_LEN]; 0171 U8 data[STR_LEN]; 0172 U8 blob_side_name[STR_LEN]; 0173 U8 blob_front_name[STR_LEN]; 0174 U8 blob_back_name[STR_LEN]; 0175 }; 0176 class CFileThing { 0177 U16 thing_template_idx; 0178 //x/y are in tiles 0179 F64 x,y,rot; 0180 U8 chat_bot_name[32]; 0181 U8 drop_item_name[32]; 0182 U8 activate_tag[32]; 0183 U8 pad[32]; 0184 }; 0185 #define DOORF_SMALL_KEY 1 0186 #define DOORF_BIG_KEY 2 0187 #define DOORF_TO_CEILING 4 0188 #define DOORF_SIDE_DOOR 8 0189 class CFileDoor { 0190 I64 x,y,act_as_wall; 0191 F64 height; 0192 I32 flags; 0193 I32 tag; 0194 }; 0195 0196 class C3DParticle:CQue { 0197 F64 x,y,z,born_at; 0198 F64 momx,momy,momz; 0199 I32 color,size; 0200 U8 splat_lump_name[STR_LEN]; 0201 Bool hit; 0202 }; 0203 0204 I64 class CWallCommand { 0205 I16 start,end; 0206 I32 dist; 0207 }; 0208 0209 #define GRID_SZ 128 0210 #define THING_RADIUS (GRID_SZ/3) 0211 #define THING_HEIGHT 1. 0212 #define DIST_SCALE (GR_HEIGHT*GRID_SZ) 0213 #define EMPTY_SPACE 0 0214 class C3DWorld { 0215 F64 fov,x,y,h,angle; 0216 F64 angle2; 0217 I64 step_width,step_width_y; 0218 I64 world_width; 0219 I64 world_height; 0220 I8 *world_blocks; //x*y*256+z 0221 I8 *world_lighting; //x*y*256+z 0222 CDC *wall_textures[0x10000/2],*to_dc; 0223 CDC *floor_textures[0x10000/2]; 0224 CDC *floor_textures1616[0x10000/2]; 0225 CDC *ceil_textures[0x10000/2]; 0226 C3DThingTemplate *thing_templates[0x10000]; 0227 I64 mp_done,dc_lock; 0228 CQue _2d_thing_templates; 0229 CI64Set *_2d_things; 0230 CI64Set *_wall_stains; 0231 CI64Set *_floor_stains; 0232 CTask *mem_task; 0233 F64 cam_height; 0234 //Private 0235 CQue particles; 0236 I64 particle_cnt; 0237 CD3 to_point[GR_WIDTH/4][GR_HEIGHT/4]; 0238 I64 things_around_camera_origin_x; 0239 I64 things_around_camera_origin_y; 0240 CI64Set *stains_around_camera[VIEW_DIST*2][VIEW_DIST*2]; 0241 }; 0242 C3DWorld *w; 0243 #define MAX_PARTICLES 128 0244 U0 NewParticle(C3DWorld *w,I64 color,I64 sz,F64 x,F64 y,F64 z,F64 mx,F64 my,F64 mz,U8 *splat_lump_name=NULL) { 0245 C3DParticle *p; 0246 if(w->particle_cnt>=MAX_PARTICLES) { 0247 w->particle_cnt--; 0248 QueRem(p=w->particles.next); 0249 Free(p); 0250 } 0251 p=CAlloc(sizeof(C3DParticle),w->mem_task); 0252 p->color=color; 0253 p->size=sz; 0254 p->x=x; 0255 p->y=y; 0256 p->z=z; 0257 p->momx=mx; 0258 p->momy=my; 0259 p->momz=mz; 0260 p->born_at=Frog_tS; 0261 if(splat_lump_name) 0262 StrCpy(p->splat_lump_name,splat_lump_name); 0263 QueIns(p,w->particles.last); 0264 w->particle_cnt++; 0265 } 0266 #define THINGF_FACE_FORWARD 1 0267 U0 C3DWorldSetFov(C3DWorld *w,F64 fov=pi/2) { 0268 w->fov=fov; 0269 } 0270 0271 #define BLOB_THINGS_ROOT "Level/Things" 0272 #define BLOB_TILES_ROOT "Level/Tiles" 0273 0274 CFrogThing *ThingTemplateSave(C3DThingTemplate *t,I64 *argv,I64 argc) { 0275 CFileThingTemplate f_template; 0276 U8 *name,*name2=NULL; 0277 if(ThingHasClass(t,"C3DThingTemplate")) { 0278 MemSet(&f_template,0,sizeof CFileThingTemplate); 0279 if(name=AsString(t->name)) { 0280 name2=MStrPrint(BLOB_THINGS_ROOT"/%s",name); 0281 StrCpy(f_template.name,name); 0282 Free(name); 0283 } 0284 if(ThingHasClass(t->front,"CFrogImg")) 0285 if(name=AsString(t->front->name)) { 0286 StrCpy(f_template.blob_front_name,name); 0287 Free(name); 0288 } 0289 if(ThingHasClass(t->back,"CFrogImg")) 0290 if(name=AsString(t->back->name)) { 0291 StrCpy(f_template.blob_back_name,name); 0292 Free(name); 0293 } 0294 if(ThingHasClass(t->side,"CFrogImg")) 0295 if(name=AsString(t->side->name)) { 0296 StrCpy(f_template.blob_side_name,name); 0297 Free(name); 0298 } 0299 if(name2) BlobFileAddLump(,name2,&f_template,sizeof(CFileThingTemplate)); 0300 Free(name2); 0301 } 0302 return FROG_SMALL_NIL; 0303 } 0304 AddMethod("C3DThingTemplate","save",&ThingTemplateSave); 0305 0306 0307 CFrogThing *TileTemplateSave(CTileTemplate *t,I64 *argv,I64 argc) { 0308 CFileTexture f_template; 0309 U8 *name; 0310 if(ThingHasClass(t,"CTileTemplate")) { 0311 MemSet(&f_template,0,sizeof CFileTexture); 0312 f_template.idx=t->tile_idx; 0313 if(ThingHasClass(t->floor_texture,"CFrogImg")) 0314 if(name=AsString(t->floor_texture->name)) { 0315 StrCpy(f_template.blob_name,name); 0316 Free(name); 0317 } 0318 if(ThingHasClass(t->wall_texture,"CFrogImg")) 0319 if(name=AsString(t->wall_texture->name)) { 0320 StrCpy(f_template.wall_blob_name,name); 0321 Free(name); 0322 } 0323 if(ThingHasClass(t->ceil_texture,"CFrogImg")) 0324 if(name=AsString(t->ceil_texture->name)) { 0325 StrCpy(f_template.ceil_blob_name,name); 0326 Free(name); 0327 } 0328 name=MStrPrint(BLOB_TILES_ROOT"/%d",t->tile_idx); 0329 BlobFileAddLump(,name,&f_template,sizeof(CFileTexture)); 0330 Free(name); 0331 } 0332 return FROG_SMALL_NIL; 0333 } 0334 AddMethod("CTileTemplate","save",&TileTemplateSave); 0335 C3DWorld *InitWorld(U8 *blob_file="ASS",F64 fov=pi/2) { 0336 C3DWorld *ret=CAlloc(sizeof(C3DWorld)); 0337 F64 xoff,yoff; 0338 U8 *tmp; 0339 I64 idx,tile,stop_at; 0340 CDC *unscaled; 0341 U16 *world_mat; 0342 C3DThingTemplate **templates=ret->thing_templates,*template; 0343 C3DThing *thing; 0344 C3DWorldManager *man; 0345 C3DWorldSetFov(ret,fov); 0346 CTileTemplate *tile_template; 0347 CDoor *door; 0348 QueInit(&ret->particles); 0349 ret->step_width=4; 0350 ret->step_width_y=4; 0351 ret->world_width=64; 0352 ret->world_height=64; 0353 ret->world_blocks=CAlloc(ret->world_width*ret->world_height*256); 0354 ret->world_lighting=CAlloc(ret->world_width*ret->world_height*256); 0355 w=ret; 0356 QueInit(&ret->_2d_thing_templates); 0357 0358 man=ConstructThing("C3DWorldManager","world_handle",ret); 0359 CallScript("init",man); 0360 ret->_wall_stains=man->wall_stains->items; 0361 ret->_floor_stains=man->floor_stains->items; 0362 ret->_2d_things=man->things->items; 0363 0364 CBlobFileHeader *bf_data=GetBlobFileData(blob_file); //Dont Free 0365 CLumpHeader *bf_lump=bf_data->lump_table; 0366 CFileThingTemplate *f_template; 0367 idx=bf_data->lump_cnt; 0368 while(--idx>=0) { 0369 if(!StrNCmp(bf_lump->name,BLOB_THINGS_ROOT,StrLen(BLOB_THINGS_ROOT))) { 0370 f_template=bf_data(U8*)+bf_lump->offset; 0371 tile=f_template->idx; 0372 if(I16_MIN<=tile<=I16_MAX) { 0373 template=ConstructThing("C3DThingTemplate"); 0374 templates[f_template->idx-I16_MIN]=template; 0375 CallScript("setFront:",template,FrogStrNew(f_template->blob_front_name)); 0376 CallScript("setBack:",template,FrogStrNew(f_template->blob_back_name)); 0377 CallScript("setSide:",template,FrogStrNew(f_template->blob_side_name)); 0378 CallScript("addThingTemplate:withName:",man,template,FrogStrNew(f_template->name)); 0379 } 0380 } 0381 bf_lump++; 0382 } 0383 CFileTexture *ftxtr; 0384 bf_lump=bf_data->lump_table; 0385 idx=bf_data->lump_cnt; 0386 while(--idx>=0) { 0387 if(!StrNCmp(bf_lump->name,BLOB_TILES_ROOT,StrLen(BLOB_TILES_ROOT))) { 0388 ftxtr=bf_data(U8*)+bf_lump->offset; 0389 tile=AbsI64(ftxtr->idx); 0390 if(0<=tile<U8_MAX) { 0391 tile_template=ConstructThing("CTileTemplate"); 0392 tile_template->tile_idx=tile; 0393 CallScript("setWall:",tile_template,FrogStrNew(ftxtr->wall_blob_name)); 0394 CallScript("setFloor:",tile_template,FrogStrNew(ftxtr->blob_name)); 0395 CallScript("setCeil:",tile_template,FrogStrNew(ftxtr->ceil_blob_name)); 0396 0397 if(ThingHasClass(tile_template->wall_texture,"CFrogImg")) { 0398 ret->wall_textures[tile]=ScaleDC(tile_template->wall_texture->dc,GRID_SZ,GRID_SZ); 0399 } 0400 if(ThingHasClass(tile_template->floor_texture,"CFrogImg")) { 0401 ret->floor_textures[tile]=ScaleDC(tile_template->floor_texture->dc,GRID_SZ,GRID_SZ); 0402 } 0403 if(ThingHasClass(tile_template->ceil_texture,"CFrogImg")) { 0404 ret->ceil_textures[tile]=ScaleDC(tile_template->ceil_texture->dc,GRID_SZ,GRID_SZ); 0405 } 0406 CallScript("addTileTemplate:",man,tile_template); 0407 } 0408 } 0409 bf_lump++; 0410 } 0411 return ret; 0412 } 0413 0414 0415 I64 BlockAtXYZ(I64 x,I64 y,I64 z) { 0416 I64 tile=x+y*w->world_width; 0417 if(0<=tile<w->world_height*w->world_width) { 0418 if(I8_MIN<=z<I8_MAX) { 0419 return w->world_blocks[tile*256+z-I8_MIN]; 0420 } 0421 } 0422 return -1; 0423 } 0424 I64 LightAtXYZ(I64 x,I64 y,I64 z) { 0425 I64 tile=x+y*w->world_width; 0426 if(0<=tile<w->world_height*w->world_width) { 0427 if(I8_MIN<=z<I8_MAX) { 0428 return w->world_lighting[tile*256+z-I8_MIN]; 0429 } 0430 } 0431 return 15; 0432 } 0433 0434 Bool IsSolidTile(I64 t) { 0435 if(!t) return FALSE; 0436 return !IsLiquidTile(t); 0437 } 0438 #define LIGHT_DECAY 1. 0439 I8 BlockLightLevel(I64 t) { 0440 if(t==13) 0441 return 15; 0442 return 0; 0443 } 0444 Bool SetLightAtXYZ(I64 x,I64 y,I64 z,I64 light) { 0445 I64 tp=x+y*w->world_width; 0446 I64 l; 0447 if(IsSolidTile(BlockAtXYZ(x,y,z))) 0448 return FALSE; 0449 if(0<=x<w->world_width) 0450 if(0<=y<w->world_height) 0451 if(I8_MIN<=z<I8_MAX) { 0452 l=w->world_lighting[tp*256+z-I8_MIN]; 0453 if(l<light) { 0454 w->world_lighting[tp*256+z-I8_MIN]=light; 0455 return TRUE; 0456 } 0457 } 0458 return FALSE; 0459 } 0460 F64 BlockAO(I64 which,I64 x,I64 y,I64 z,I64 sidex,I64 sidey,I64 sidez) { 0461 I64 cnt=0; 0462 static I64 offs1[6]={-1,0,1,0,-1,0}; 0463 I64 corner=0; 0464 if(sidez) { 0465 if(BlockAtXYZ(x+offs1[which],y+offs1[1+which],z+sidez)) 0466 cnt++; 0467 if(BlockAtXYZ(x+offs1[which+1],y+offs1[1+which+1],z+sidez)) 0468 cnt++; 0469 if(cnt==2) return 0; 0470 return 3-corner-cnt; 0471 } 0472 if(sidex) { 0473 if(BlockAtXYZ(x+sidex,y+offs1[which],z+offs1[1+which])) 0474 cnt++; 0475 if(BlockAtXYZ(x+sidex,y+offs1[which+1],z+offs1[1+which+1])) 0476 cnt++; 0477 if(cnt==2) return 0; 0478 return 3-corner-cnt; 0479 } 0480 if(sidey) { 0481 if(BlockAtXYZ(x+offs1[which],y+sidey,z+offs1[1+which])) 0482 cnt++; 0483 if(BlockAtXYZ(x+offs1[which+1],y+sidey,z+offs1[1+which+1])) 0484 cnt++; 0485 if(cnt==2) return 0; 0486 return 3-corner-cnt; 0487 } 0488 return 0; 0489 } 0490 0491 F64 CornerLight(I64 which,I64 x,I64 y,I64 z,I64 sidex,I64 sidey,I64 sidez) { 0492 static I64 offs1[8]={-1,0,0,-1,1,0,0,1}; 0493 which<<=1; 0494 if(sidez) { 0495 if(BlockAtXYZ(x+offs1[which],y+offs1[1+which],z+sidez)) 0496 return LightAtXYZ(x,y,z+sidez); 0497 return LightAtXYZ(x+offs1[which],y+offs1[1+which],z+sidez); 0498 } 0499 if(sidey) { 0500 if(BlockAtXYZ(x+offs1[which],y+sidey,z+offs1[1+which])) 0501 return LightAtXYZ(x,y+sidey,z); 0502 return LightAtXYZ(x+offs1[which],y+sidey,z+offs1[1+which]); 0503 } 0504 if(sidex) { 0505 if(BlockAtXYZ(x+sidex,y+offs1[which],z+offs1[1+which])); 0506 return LightAtXYZ(x+sidex,y,z); 0507 return LightAtXYZ(x+sidex,y+offs1[which],z+offs1[1+which]); 0508 } 0509 return 0; 0510 } 0511 0512 0513 U0 LightingLight(I64 x,I64 y,I64 z,I64 light) { 0514 CI64Set *stack=I64SetNew,*stack2=I64SetNew; 0515 CI64Set *visited=I64SetNew; 0516 I64 xo,yo,zo,dummy; 0517 I64 time=0; 0518 I64SetAdd(stack,x); 0519 I64SetAdd(stack,y); 0520 I64SetAdd(stack,z); 0521 do { 0522 while(stack->cnt>0) { 0523 z=stack->body[--stack->cnt]; 0524 y=stack->body[--stack->cnt]; 0525 x=stack->body[--stack->cnt]; 0526 dummy.u16[0]=x; 0527 dummy.u16[1]=y; 0528 dummy.i16[2]=z; 0529 dummy.i16[3]=0; 0530 if(I64SetHas(visited,dummy)) 0531 goto n; 0532 I64SetAdd(visited,dummy); 0533 for(zo=-1;zo<=1;zo+=2) { 0534 if(SetLightAtXYZ(x,y,z+zo,light)) { 0535 I64SetAdd(stack2,x); 0536 I64SetAdd(stack2,y); 0537 I64SetAdd(stack2,z+zo); 0538 } 0539 } 0540 for(xo=-1;xo<=1;xo+=2) { 0541 if(SetLightAtXYZ(x+xo,y,z,light)) { 0542 I64SetAdd(stack2,x+xo); 0543 I64SetAdd(stack2,y); 0544 I64SetAdd(stack2,z); 0545 } 0546 } 0547 for(yo=-1;yo<=1;yo+=2) { 0548 if(SetLightAtXYZ(x,y+yo,z,light)) { 0549 I64SetAdd(stack2,x); 0550 I64SetAdd(stack2,y+yo); 0551 I64SetAdd(stack2,z); 0552 } 0553 } 0554 n:; 0555 } 0556 SwapI64(&stack2,&stack); 0557 } while(--light>0); 0558 I64SetDel(visited); 0559 I64SetDel(stack2); 0560 I64SetDel(stack); 0561 } 0562 U0 LightingSky(I64 x,I64 y,I64 sky_light=16,I64 shadow_color=BLACK) { 0563 I64 z=I8_MAX,b; 0564 U8 *col; 0565 U8 *lcol; 0566 Bool sky=TRUE; 0567 F64 level=sky_light; 0568 I64 tp=x+y*w->world_width; 0569 if(0<=x<w->world_width) 0570 if(0<=y<w->world_height) { 0571 col=&w->world_blocks[tp*256+z-I8_MIN]; 0572 lcol=&w->world_lighting[tp*256+z-I8_MIN]; 0573 while(z>=I8_MIN) { 0574 b=col[z-I8_MIN]; 0575 if(IsSolidTile(b)) { 0576 sky=FALSE; 0577 } 0578 if(!sky) 0579 level=0; 0580 lcol[z-I8_MIN]=MaxI64(ToI64(level),0); 0581 --z; 0582 } 0583 } 0584 } 0585 CFrogThing *WorldLightingSky(C3DWorldManager *man,I64 *argv,I64 argc) { 0586 I64 x=w->x/128.,ix; 0587 I64 y=w->y/128.,iy; 0588 I64 sky_light=AsF64(argv[0]),z,tp; 0589 I64 level; 0590 //Sky light 0591 for(ix=-VIEW_DIST*2;ix<VIEW_DIST*2;ix++) { 0592 for(iy=-VIEW_DIST*2;iy<VIEW_DIST*2;iy++) { 0593 LightingSky(ix+x,iy+y,sky_light); 0594 } 0595 } 0596 //Pass2 world lights 0597 for(ix=-VIEW_DIST*2;ix<VIEW_DIST*2;ix++) { 0598 for(iy=-VIEW_DIST*2;iy<VIEW_DIST*2;iy++) { 0599 z=I8_MAX; 0600 while(z>=I8_MIN) { 0601 if(1<=(level=BlockLightLevel(BlockAtXYZ(x+ix,y+iy,z)))) { 0602 LightingLight(x+ix,y+iy,z,level); 0603 } 0604 --z; 0605 } 0606 } 0607 } 0608 } 0609 AddMethod("C3DWorldManager","skylight:",&WorldLightingSky); 0610 Bool HeightImpossible(C3DWorld *w,I64 ix,I64 iy,F64 above,Bool allow_ceil,F64 tallness=.1,F64 wiggle_room=0) { 0611 I64 iz=Floor(above); 0612 I64 c,idx2,t; 0613 F64 h; 0614 if(!(-128<iz<128)) return FALSE; 0615 if(0>ix) return TRUE; 0616 if(w->world_width<=ix) return TRUE; 0617 if(0>iy) return TRUE; 0618 if(w->world_height<=iy) return TRUE; 0619 if(IsSolidTile(BlockAtXYZ(ix,iy,iz))) { 0620 return TRUE; 0621 } 0622 for(idx2=0;idx2<tallness;idx2++) { 0623 idx2++; 0624 if(IsSolidTile(BlockAtXYZ(ix,iy,iz+idx2))) 0625 return TRUE; 0626 } 0627 return FALSE; 0628 } 0629 0630 C3DThing *BumpsIntoThing(C3DThing *self,I64 *argv,I64 argc) { 0631 C3DThing *who=argv[0]; 0632 F64 radius=THING_RADIUS*THING_RADIUS; 0633 F64 x,y; 0634 x=who->x-self->x; 0635 y=who->y-self->y; 0636 if(Max(self->z,who->z) 0637 <=Min(self->z+THING_HEIGHT,who->z+THING_HEIGHT)) 0638 if(radius>=x*x+y*y) 0639 return FrogNumNew(1); 0640 return FrogNumNew(0); 0641 } 0642 AddMethod("C3DThing","hitsThing:",&BumpsIntoThing); 0643 CFrogNum *C3DThingPathFindWalkTowardsThing(C3DThing *self,I64 *argv,I64 argc) { 0644 CPFPoint pt; 0645 C3DThing *thing=argv[0]; 0646 if(!ThingHasClass(thing,"C3DThing")) return FROG_SMALL_NIL; 0647 CI64Set *path=PathFinder(self->x/128,self->y/128,Floor(self->z),thing->x/128,thing->y/128,Floor(thing->z),&BlockAtXYZ,AsF64(argv[1])); 0648 if(path->cnt<2) { 0649 I64SetDel(path); 0650 return FrogNumNew(Arg(thing->x-self->x,thing->y-self->y)); 0651 } 0652 //TODO account for large same direction 0653 pt=path->body[1]; 0654 I64SetDel(path); 0655 return FrogNumNew(Arg(pt.x+.5-self->x/128,pt.y+.5-self->y/128)); 0656 } 0657 AddMethod("C3DThing","pathFinderAngleTowardsThing:withJump:",&C3DThingPathFindWalkTowardsThing); 0658 #define RADF_CEIL 1 0659 #define RADF_FLOOR 2 0660 #define RADF_DOOR 4 0661 Bool RadiusHitsWall(C3DWorld *w,F64 angle,F64 *_x,F64 *_y,F64 height,F64 radius=THING_RADIUS,Bool adjust=FALSE,F64 tallness=.8,I64 flags=RADF_CEIL|RADF_FLOOR) { 0662 F64 x=*_x; 0663 F64 y=*_y; 0664 x/=GRID_SZ; 0665 y/=GRID_SZ; 0666 radius/=GRID_SZ; 0667 F64 by=1/4.; 0668 Bool ret=FALSE,hit=TRUE; 0669 I64 xoff,yoff,ch,cr,tile,i; 0670 F64 tx,ty,h; 0671 do { 0672 hit=FALSE; 0673 for(i=0;i!=4;i++) { 0674 for(xoff=-1;xoff<2;xoff++) 0675 for(yoff=-1;yoff<2;yoff++) { 0676 if(xoff^^yoff) { 0677 switch(xoff) { 0678 case -1: 0679 tx=Floor(x); 0680 break; 0681 case 0: 0682 tx=x; 0683 break; 0684 case 1: 0685 tx=Ceil(x); 0686 break; 0687 } 0688 switch(yoff) { 0689 case -1: 0690 ty=Floor(y); 0691 break; 0692 case 0: 0693 ty=y; 0694 break; 0695 case 1: 0696 ty=Ceil(y); 0697 break; 0698 } 0699 //ONLY CHECK FOR WALL WE ARE WALKING TOWARDS 0700 if(xoff) { 0701 if(Sign(Cos(angle))!=xoff) 0702 goto skip; 0703 } 0704 if(yoff) { 0705 if(Sign(Sin(angle))!=yoff) 0706 goto skip; 0707 } 0708 if(HeightImpossible(w,x+xoff,y+yoff,height,TRUE,tallness)) { 0709 //.2 for stepping over partly open doors 0710 check: 0711 if(Abs(x-tx)<=radius&&xoff) { 0712 if(adjust) { 0713 x=tx+radius*1.05*-xoff; 0714 hit=TRUE; 0715 } 0716 ret|=TRUE; 0717 } 0718 if(Abs(y-ty)<=radius&&yoff) { 0719 if(adjust) { 0720 y=ty+radius*1.05*-yoff; 0721 hit=TRUE; 0722 } 0723 ret|=TRUE; 0724 } 0725 } 0726 skip:; 0727 } 0728 } 0729 } 0730 } while(hit); 0731 if(adjust) { 0732 *_x=x*GRID_SZ; 0733 *_y=y*GRID_SZ; 0734 } 0735 return ret; 0736 } 0737 Bool C3DWorldMoveZWithCollision(C3DWorld *w,F64 dist,F64 x,F64 y,F64 *_height,F64 tallness=.8) { 0738 F64 height=*_height; 0739 F64 z=height; 0740 F64 o=height; 0741 F64 by=dist/8; 0742 Bool hit=FALSE; 0743 F64 h_offset=0; 0744 F64 h,delta; 0745 I64 cnt=0,tile,best,ch,cr; 0746 F64 dir=Sign(dist); 0747 F64 oz=z; 0748 //Wut 0749 if(dir==0) return FALSE; 0750 for(cnt=0;Abs(dist)>1/256.;cnt++) { 0751 if(dir<0) 0752 delta=Max(dist,-1); 0753 else 0754 delta=Min(dist,1); 0755 dist-=delta; 0756 if(HeightImpossible(w,x/128,y/128,z+delta,TRUE,tallness)) { 0757 hit=TRUE; 0758 goto fix; 0759 } 0760 z+=delta; 0761 } 0762 fix:; 0763 while(HeightImpossible(w,x/GRID_SZ,y/GRID_SZ,z,TRUE,tallness)) { 0764 hit=TRUE; 0765 z-=dir/128.; 0766 if(dir>0&&z<oz) { 0767 z=oz; 0768 break; 0769 } if(dir<0&&z>oz) { 0770 z=oz; 0771 break; 0772 } 0773 } 0774 0775 //Cant move anywhere but up 0776 if(z==oz) { 0777 while(HeightImpossible(w,x/GRID_SZ,y/GRID_SZ,z,TRUE,tallness)) 0778 ++z; 0779 } 0780 0781 if(hit) 0782 if(Abs(z-Floor(z))<=2*dir/128.) 0783 z=Floor(z); 0784 *_height=z; 0785 return hit; 0786 } 0787 //Returns true on wall hit 0788 Bool C3DWorldMoveWithCollision(C3DWorld *w,F64 angle,F64 dist,F64 *x,F64 *y,Bool adjust_smart=TRUE,F64 height=0) { 0789 F64 dist2=0,boundary; 0790 Bool hit_wall=FALSE,force; 0791 F64 old_x=w->x,old_y=w->y,deflect_angle; 0792 w->x=*x,w->y=*y; 0793 I64 at_tile; 0794 if(dist<0.) angle+=pi,dist=-dist; 0795 I64 idx,idx2; 0796 I64 h,ch,cr; 0797 if(RadiusHitsWall(w,angle,x,y,height,THING_RADIUS,TRUE,,RADF_CEIL|RADF_FLOOR|RADF_DOOR)) { 0798 hit_wall=TRUE; 0799 goto fin; 0800 } 0801 if(adjust_smart) 0802 while(dist2<dist) { 0803 for(idx=0;idx!=5;idx++) { 0804 dist2+=GRID_SZ/5.; 0805 if(dist2>=dist) dist2=dist; 0806 *x=w->x+Cos(angle)*dist2; 0807 *y=w->y+Sin(angle)*dist2; 0808 if(RadiusHitsWall(w,angle,x,y,height,THING_RADIUS,TRUE,,RADF_CEIL|RADF_FLOOR|RADF_DOOR)) { 0809 hit_wall=TRUE; 0810 goto fin; 0811 } 0812 if(HeightImpossible(w,*x/GRID_SZ,*y/GRID_SZ,height,TRUE,,.2)) {//.2 wiggle room for stepping over partly open doors 0813 //Totally reject move,something when wrong 0814 // (would be placed on top of unreachable wall) 0815 *x=w->x; 0816 *y=w->y; 0817 hit_wall=TRUE; 0818 goto fin; 0819 } 0820 if(dist2>=dist) 0821 goto fin; 0822 } 0823 } 0824 fin: 0825 if(!(0<=w->x/128.<w->world_width)|| 0826 !(0<=w->y/128.<w->world_height) 0827 ) { 0828 if(x) 0829 *x=Clamp(w->x/128.,0.,w->world_width)*128; 0830 if(y) 0831 *y=Clamp(w->y/128.,0.,w->world_height)*128; 0832 hit_wall=TRUE; 0833 } 0834 w->x=old_x,w->y=old_y; 0835 return hit_wall; 0836 } 0837 Bool AdjustRadiusThing(C3DWorld *w,C3DThing *self,C3DThing *other,F64 angle) { 0838 F64 sr=THING_RADIUS; 0839 F64 or=THING_RADIUS; 0840 F64 dist,push_back; 0841 I64 attempt=0; 0842 Bool ret=FALSE; 0843 again: 0844 dist=Sqrt(Sqr(other->x-self->x)+Sqr(other->y-self->y)); 0845 if(dist<or+sr) { 0846 ret=TRUE; 0847 push_back=(sr+or-dist)*.1*1.4; 0848 C3DWorldMoveWithCollision(w,angle+pi,push_back, 0849 &self->x, 0850 &self->y, 0851 TRUE, //Slide along wall 0852 self->z); 0853 if(++attempt<15) goto again; 0854 } 0855 return ret; 0856 } 0857 0858 Bool IsOnWaterTile(C3DThing *t) { 0859 return 5==BlockAtXYZ(t->x/GRID_SZ,t->y/GRID_SZ,Floor(t->z)-1); 0860 } 0861 Bool IsOnLavaTile(C3DThing *t) { 0862 return 10==BlockAtXYZ(t->x/GRID_SZ,t->y/GRID_SZ,Floor(t->z)-1); 0863 } 0864 CFrogNum *WorldManagerRemoveFromGrid(C3DWorldManager *wm,I64 *argv,I64 argc) { 0865 C3DThing *t=argv[0]; 0866 if(!ThingHasClass(t,"C3DThing")) return FROG_SMALL_NIL; 0867 CFrogArray *arr=wm->grid; 0868 I64 atx=t->x/GRID_SZ/4.; 0869 I64 aty=t->y/GRID_SZ/4.; 0870 if(atx<0||aty<0) return FROG_SMALL_NIL; 0871 if(atx>=w->world_width/4+1) return FROG_SMALL_NIL; 0872 if(aty>=w->world_height/4+1) return FROG_SMALL_NIL; 0873 arr=arr->items->body[atx]; 0874 arr=arr->items->body[aty]; 0875 if(I64SetHas(arr->items,t)) { 0876 I64SetRem(arr->items,t); 0877 } else { 0878 for(atx=0;atx<w->world_width/4+1;atx++) { 0879 for(aty=0;aty<w->world_height/4+1;aty++) { 0880 arr=wm->grid; 0881 arr=arr->items->body[atx]; 0882 arr=arr->items->body[aty]; 0883 I64SetRem(arr->items,t); 0884 } 0885 } 0886 } 0887 return FROG_SMALL_NIL; 0888 } 0889 AddMethod("C3DWorldManager","removeFromGrid:",&WorldManagerRemoveFromGrid); 0890 CFrogNum *WorldManagerUpdateThingPos(C3DWorldManager *wm,I64 *argv,I64 argc) { 0891 C3DThing *t=argv[0]; 0892 if(!ThingHasClass(t,"C3DThing")) return FROG_SMALL_NIL; 0893 CFrogArray *arr=wm->grid; 0894 I64 atx=t->x/GRID_SZ/4.; 0895 I64 aty=t->y/GRID_SZ/4.; 0896 if(atx<0||aty<0) return FROG_SMALL_NIL; 0897 if(atx>=w->world_width/4+1) return FROG_SMALL_NIL; 0898 if(aty>=w->world_height/4+1) return FROG_SMALL_NIL; 0899 arr=arr->items->body[atx]; 0900 arr=arr->items->body[aty]; 0901 if(!I64SetHas(arr->items,t)) 0902 I64SetAdd(arr->items,t); 0903 return FROG_SMALL_NIL; 0904 } 0905 AddMethod("C3DWorldManager","updateThingPos:",&WorldManagerUpdateThingPos); 0906 CFrogArray *WorldManagerThingsInRadius(C3DWorldManager *wm,I64 *argv,I64 argc) { 0907 CFrogArray *arr=wm->grid,*ret=FrogArrayNew; 0908 C3DThing *t,**body; 0909 F64 x=AsF64(argv[0]),y=AsF64(argv[1]); 0910 I64 b_atx=x/GRID_SZ/4.,atx; 0911 I64 b_aty=y/GRID_SZ/4.,aty; 0912 I64 ox,oy,cnt; 0913 F64 r=AsF64(argv[2]); 0914 I64 ir=Ceil(r/128./4.+.001); 0915 for(ox=-ir;ox<=ir;ox++) 0916 for(oy=-ir;oy<=ir;oy++) { 0917 atx=ox+b_atx; 0918 aty=oy+b_aty; 0919 if(atx<0||aty<0) goto next; 0920 if(atx>=w->world_width/4+1) goto next; 0921 if(aty>=w->world_height/4+1) goto next; 0922 arr=wm->grid; 0923 arr=arr->items->body[atx]; 0924 arr=arr->items->body[aty]; 0925 cnt=arr->items->cnt; 0926 body=arr->items->body; 0927 while(--cnt>=0) { 0928 t=body[cnt]; 0929 if(r*r>=Sqr(t->x-x)+Sqr(t->y-y)) { 0930 I64SetAdd(ret->items,t); 0931 } 0932 } 0933 next:; 0934 } 0935 return ret; 0936 } 0937 AddMethod("C3DWorldManager","getThingsInRadiusFromX:fromY:withRadius:",&WorldManagerThingsInRadius); 0938 U0 PhysicsOnThing(C3DWorld *w,C3DThing *t,C3DWorldManager *wm,F64 last_tS) { 0939 I64 wx=t->x/GRID_SZ,wy=t->y/GRID_SZ,idx; 0940 if(!(0<=wx<w->world_width)) 0941 return; 0942 if(!(0<=wy<w->world_height)) 0943 return; 0944 //I get about 20 fps on my aspire 5920(add 5 fps) 0945 F64 weight=1.; 0946 F64 angle,dist,ox,oy; 0947 I64 tile=wx+wy*w->world_width; 0948 Bool i_am_moving=FALSE,on_ground; 0949 CRocket *rocket=NULL; 0950 CFrogArray *in_radius; 0951 CDoor *to_open; 0952 C3DThing *other; 0953 CI64Set *set; 0954 if(ThingHasClass(t,"CRocket")) 0955 rocket=t; 0956 WorldManagerRemoveFromGrid(wm,&t,1); 0957 if(C3DWorldMoveZWithCollision(w,t->momz*weight+t->momz2*weight,t->x,t->y,&t->z)) { 0958 if(!rocket) //Explode later(computer hitting floor after we move x/y) 0959 t->momz=0; 0960 } else if(!rocket&&!t->floating) { 0961 if(IsLiquidTile(BlockAtXYZ(t->x/128,t->y/128,t->z))) { 0962 t->momz=t->momz2-wm->gravity/3*weight; 0963 } else 0964 t->momz-=wm->gravity*weight; 0965 } 0966 ox=t->x; 0967 oy=t->y; 0968 if(t->momy+t->momy2||t->momx+t->momx2) { 0969 if(!rocket) { 0970 t->momx*=29/30.*weight; 0971 t->momy*=29/30.*weight; 0972 if(Sign(t->momx)==-Sign(t->momx2)) 0973 t->momx+=t->momx2*weight; 0974 if(Sign(t->momy)==-Sign(t->momy2)) 0975 t->momy+=t->momy2*weight; 0976 if(Abs(t->momx)<2) t->momx=0; 0977 if(Abs(t->momy)<2) t->momy=0; 0978 } 0979 //Handle slow 0980 if(ThingHasClass(t,"CPlayer")) { 0981 t->friction=0.; 0982 if(IsOnWaterTile(t)) { 0983 t->friction=.25; 0984 } else if(IsOnLavaTile(t)) { 0985 t->friction=.5; 0986 } 0987 } 0988 angle=Arg(t->momx+t->momx2,t->momy+t->momy2); 0989 i_am_moving=TRUE; 0990 dist=Sqrt(Sqr(t->momx+t->momx2)+Sqr(t->momy+t->momy2))*(1.-t->friction); 0991 on_ground=AsF64(CallScript("isOnGround",t)); 0992 if(C3DWorldMoveWithCollision(w,angle,dist*weight, 0993 &t->x, 0994 &t->y, 0995 TRUE, 0996 t->z)) { 0997 0998 hit: 0999 t->momx=0.; 1000 t->momy=0.; 1001 if(rocket) { 1002 explode: 1003 CallScript("explode",rocket); 1004 return; 1005 } else if(!ThingHasClass(t,"CPickup")) { 1006 to_open=CallScript("doorInRadius:atX:atY:atAngle:", 1007 wm,FrogNumNew(THING_RADIUS),FrogNumNew(t->x),FrogNumNew(t->y),FrogNumNew(t->angle)); 1008 if(ThingHasClass(to_open,"CDoor")) { 1009 CallScript("activateBy:",to_open,t); 1010 } 1011 } 1012 } 1013 if(t->no_fall_off_edge&&on_ground) { 1014 if(AsF64(CallScript("isOverEdge",t))) { 1015 t->x=ox; 1016 t->y=oy; 1017 CallScript("update",t); //New Chase Dir 1018 } 1019 } 1020 } else if(RadiusHitsWall(w,angle,&t->x,&t->y,t->z,THING_RADIUS,TRUE,,RADF_CEIL|RADF_FLOOR|RADF_DOOR)) 1021 goto hit; 1022 if(rocket) { 1023 if(!(0.<=t->x<w->world_width*128)) 1024 goto explode; 1025 if(!(0.<=t->y<w->world_height*128)) 1026 goto explode; 1027 if(AsF64(CallScript("checkExplode",rocket))) 1028 return; 1029 } 1030 //Only check for thing collision if we are the ones movin 1031 if(i_am_moving&&!rocket) { 1032 in_radius=CallScript("getObstaclesInRadiusForThing:inRadius:",wm,t,FrogNumNew(2*THING_RADIUS)); 1033 set=in_radius->items; 1034 for(idx=0;idx!=set->cnt;idx++) { 1035 other=set->body[idx]; 1036 if(other!=t&&Max(other->z,t->z)<=Min(other->z+THING_HEIGHT,t->z+THING_HEIGHT)) 1037 if(AdjustRadiusThing(w,t,other,angle)) 1038 t->hit_thing=TRUE; 1039 } 1040 } 1041 if(rocket) { 1042 if(HeightImpossible(w,t->x/GRID_SZ,t->y/GRID_SZ,t->z,TRUE,1.)) 1043 goto explode; 1044 } 1045 WorldManagerUpdateThingPos(wm,&t,1); 1046 } 1047 F64 Lerp(F64 per,F64 min,F64 max) { 1048 if(min<max) 1049 return Clamp(per*(max-min)+min,min,max); 1050 return Clamp(per*(max-min)+min,max,min); 1051 } 1052 1053 //-1 terminated 1054 //https://github.com/cgyurgyik/fast-voxel-traversal-algorithm/blob/master/overview/FastVoxelTraversalOverview.md 1055 I64 *GetTilesInPath(C3DWorld *w,F64 angle,F64 dist) { 1056 CI64Set *t=I64SetNew; 1057 F64 x=w->x/128,y=w->y/128,slope,cos,sin; 1058 I64 tx=x/GRID_SZ,ty=y/GRID_SZ,idx; 1059 I64 cnt=dist/128.; 1060 Bool x_type; 1061 cos=Cos(angle); 1062 sin=Sin(angle); 1063 I64 stepx=Sign(cos); 1064 I64 stepy=Sign(sin); 1065 F64 current_x_index=Max(1,Ceil(x)); 1066 F64 current_y_index=Max(1,Ceil(y)); 1067 if(cos<0) current_x_index--; 1068 if(sin<0) current_y_index--; 1069 F64 tMaxX=(current_x_index-x)/cos; 1070 F64 tMaxY=(current_y_index-y)/sin; 1071 tx=x; 1072 ty=y; 1073 idx=ty*w->world_width+tx; 1074 I64SetAdd(t,idx); 1075 while(--cnt>=0) { 1076 if(tMaxX<tMaxY) { 1077 tMaxX+=1./Abs(cos); 1078 tx+=stepx; 1079 } else { 1080 tMaxY+=1./Abs(sin); 1081 ty+=stepy; 1082 } 1083 1084 if(0<=tx<w->world_width) 1085 if(0<=ty<w->world_height) { 1086 idx=ty*w->world_width+tx; 1087 I64SetAdd(t,idx); 1088 goto pass; 1089 } 1090 break; 1091 pass:; 1092 } 1093 fin: 1094 I64SetAdd(t,-1); 1095 I64 *tiles=t->body; 1096 Free(t); 1097 return tiles; 1098 } 1099 1100 extern CDC *WhichTexture(C3DWorld *w,I64 tile,F64 h,F64 h2,F64 *hit_h,Bool *hit_wall); 1101 CDC *ThingFace(C3DWorld *w,C3DThing *thing,Bool *flip=NULL) { 1102 C3DThingTemplate *template=thing->template; 1103 if(template==FROG_SMALL_NIL) return NULL; 1104 F64 off=thing->angle-w->angle+pi,gap; 1105 I64 face=1; 1106 off=off%(2*pi); 1107 CDC *use_dc=NULL; 1108 I64 frame; 1109 F64 diff; 1110 for(gap=0.;gap<2*pi;gap+=2.*pi/4.) { 1111 diff=(off-gap+3*pi)%(2*pi)-pi; 1112 //https://stackoverflow.com/questions/12234574/calculating-if-an-angle-is-between-two-angles 1113 if(-2*pi/4./2<=diff<=2*pi/4./2) 1114 break; 1115 face++; 1116 } 1117 if(flip) *flip=FALSE; 1118 switch(face) { 1119 default: 1120 case 1: 1121 use_dc=template->front; 1122 break; 1123 case 2: 1124 use_dc=template->side; 1125 if(flip) *flip=TRUE; 1126 break; 1127 case 3: 1128 use_dc=template->back; 1129 break; 1130 case 4: 1131 use_dc=template->side; 1132 break; 1133 } 1134 draw: 1135 if(!ThingHasClass(use_dc,"CFrogImg")) return NULL; 1136 use_dc=use_dc(CFrogImg*)->dc; 1137 if(!use_dc||!AnimDCCnt(use_dc)) return NULL; 1138 frame=ToI64((Frog_tS-thing->animation_start_tS)/ANIM_DELAY); 1139 frame=MaxI64(frame,0); //Prevent poo poo suace 1140 if(thing->animation_no_repeat) 1141 use_dc+=MinI64(frame,AnimDCCnt(use_dc)-1); 1142 else 1143 use_dc+=frame%AnimDCCnt(use_dc); 1144 return use_dc; 1145 } 1146 1147 1148 Bool PointToScrn(C3DWorld *w,F64 x,F64 y,F64 z,CD3 *p) { 1149 z-=w->cam_height; 1150 y=(y-w->y)/128; 1151 x=(x-w->x)/128; 1152 F64 o=Sqrt(z*z+x*x+y*y); 1153 CD3 view_plane; 1154 CD3 pt1; 1155 pt1.z=z; 1156 pt1.x=x*Cos(-w->angle)-y*Sin(-w->angle); 1157 pt1.y=x*Sin(-w->angle)+y*Cos(-w->angle); 1158 x=pt1.x; 1159 y=pt1.y; 1160 pt1.x=x*Cos(w->angle2)-z*Sin(w->angle2); 1161 pt1.z=x*Sin(w->angle2)+z*Cos(w->angle2); 1162 x=pt1.x; 1163 z=pt1.z; 1164 1165 p->x=x; 1166 p->y=y; 1167 p->z=z; 1168 1169 //Begind camera 1170 if(p->x<=1e-2) { 1171 p->x=1e-2; 1172 D3MulEqu(p,1./p->x); 1173 D3Equ(p, 1174 (p->y/2+.5)*GR_WIDTH, 1175 (p->z/-2+.5)*GR_HEIGHT, 1176 o*128 1177 ); 1178 return FALSE; 1179 } else { 1180 D3MulEqu(p,1./p->x); 1181 D3Equ(p, 1182 (p->y/2+.5)*GR_WIDTH, 1183 (p->z/-2+.5)*GR_HEIGHT, 1184 o*128 1185 ); 1186 return TRUE; 1187 } 1188 } 1189 1190 1191 U0 Mat4x4MulXYZ_F64(F64 *r,F64 *_x,F64 *_y,F64 *_z) 1192 { 1193 F64 x1,y1,z1,xx=*_x,yy=*_y,zz=*_z; 1194 x1=(r[0*4+0]*xx+r[0*4+1]*yy+r[0*4+2]*zz+r[0*4+3]); 1195 y1=(r[1*4+0]*xx+r[1*4+1]*yy+r[1*4+2]*zz+r[1*4+3]); 1196 z1=(r[2*4+0]*xx+r[2*4+1]*yy+r[2*4+2]*zz+r[2*4+3]); 1197 *_x=x1;*_y=y1;*_z=z1; 1198 } 1199 1200 1201 U0 PointsToMat(CD3 *corners,F64 *mat) { 1202 //https://math.stackexchange.com/questions/186286/get-transformation-matrix-from-points 1203 F64 x1=corners[0].x; 1204 F64 x2=corners[1].x; 1205 F64 x3=corners[2].x; 1206 F64 x4=corners[3].x; 1207 1208 F64 y1=corners[0].y; 1209 F64 y2=corners[1].y; 1210 F64 y3=corners[2].y; 1211 F64 y4=corners[3].y; 1212 1213 F64 i=1; 1214 1215 1216 F64 j = (y1 - y2 + y3 - y4) / (y2 - y3); 1217 F64 k = (x1 - x2 + x3 - x4) / (x4 - x3); 1218 F64 m = (y4 - y3) / (y2 - y3); 1219 F64 n = (x2 - x3) / (x4 - x3); 1220 1221 F64 h,g; 1222 if((1-m*n)==0.||y2==y3||x4==x3) 1223 h=0,g=0; 1224 else { 1225 h = i * (j - k * m) / (1 - m * n); 1226 g = i * (k - j * n) / (1 - m * n); 1227 } 1228 F64 c = x1 * i; 1229 F64 f = y1 * i; 1230 F64 a = x4 * (g + i) - x1 * i; 1231 F64 b = x2 * (h + i) - x1 * i; 1232 F64 d = y4 * (g + i) - y1 * i; 1233 F64 e = y2 * (h + i) - y1 * i; 1234 1235 mat[0]=a; 1236 mat[1]=b; 1237 mat[2]=c; 1238 mat[3]=d; 1239 mat[4]=e; 1240 mat[5]=f; 1241 mat[6]=g; 1242 mat[7]=h; 1243 mat[8]=i; 1244 1245 } 1246 U0 Mat3x3Inv(F64 *matrix) { 1247 F64 a=matrix[0]; 1248 F64 b=matrix[1]; 1249 F64 c=matrix[2]; 1250 F64 d=matrix[3]; 1251 F64 e=matrix[4]; 1252 F64 f=matrix[5]; 1253 F64 g=matrix[6]; 1254 F64 h=matrix[7]; 1255 F64 i=matrix[8]; 1256 //https://stackoverflow.com/questions/63981471/how-do-i-solve-inverse-of-3x3-matrices-without-using-a-library 1257 F64 xx=e*i-h*f; 1258 F64 yy=f*g-d*i; 1259 F64 zz=d*h-g*e; 1260 F64 det=a*xx+b*yy+c*zz; 1261 matrix[0]=xx/det; 1262 matrix[1]=(c*h-b*i)/det; 1263 matrix[2]=(b*f-c*e)/det; 1264 matrix[3]=yy/det; 1265 matrix[4]=(a*i-c*g)/det; 1266 matrix[5]=(d*c-a*f)/det; 1267 matrix[6]=zz/det; 1268 matrix[7]=(g*b-a*h)/det; 1269 matrix[8]=(a*e-d*b)/det; 1270 } 1271 1272 Bool DrawQuad(C3DWorld *w,CDC *texture,CD3 *points,Bool record=FALSE) { 1273 CD3 screen[4],dummya,dummyb,dummyc; 1274 I64 i,x,y; 1275 I64 idist; 1276 I32 *depth_b; 1277 F64 mat[9]; 1278 F64 tx,ty,tz,dist; 1279 F64 lxt,lyt,hxt,hyt; //Texture cordnates 1280 CDC *dc=w->to_dc; 1281 U8 *dst; 1282 Bool hit=FALSE; 1283 Bool found=FALSE,failed=FALSE; 1284 I64 failed2=0; 1285 I64 force_color=0; 1286 F64 farest=0; 1287 for(i=0;i!=4;i++) { 1288 hit=PointToScrn(w,points[i].x,points[i].y,points[i].z,&screen[i]); 1289 found|=hit; 1290 failed|=!hit; 1291 if(!hit) { 1292 Bts(&failed2,i); 1293 } 1294 dist=Sqrt( 1295 Sqr(points[i].x-w->x)+ 1296 Sqr(points[i].y-w->y)+ 1297 Sqr((points[i].z-w->cam_height)*128)); 1298 if(dist>farest) 1299 farest=dist; 1300 } 1301 if(!found) return FALSE; 1302 hit=FALSE; 1303 PointsToMat(screen,mat); 1304 Mat3x3Inv(mat); 1305 I64 lx=screen[0].x,hx=screen[0].x; 1306 I64 ly=screen[0].y,hy=screen[0].y; 1307 for(i=1;i!=4;i++) { 1308 lx=MinI64(lx,screen[i].x); 1309 ly=MinI64(ly,screen[i].y); 1310 hx=MaxI64(hx,screen[i].x); 1311 hy=MaxI64(hy,screen[i].y); 1312 } 1313 lx--; 1314 ly--; 1315 hx++; 1316 hy++; 1317 lx&=~3; 1318 ly&=~3; 1319 if(hy&3) hy=hy&~3+4; 1320 if(hx&3) hx=hx&~3+4; 1321 lx=ClampI64(lx,0,GR_WIDTH-4); 1322 ly=ClampI64(ly,0,GR_HEIGHT-4); 1323 hy=ClampI64(hy,0,GR_HEIGHT-4); 1324 hx=ClampI64(hx,0,GR_WIDTH-4); 1325 idist=ToI64(farest); 1326 idist|=idist<<32; 1327 for(x=lx;x<hx;x+=4) { 1328 dst=&dc->body[x+ly*dc->width_internal]; 1329 depth_b=&dc->depth_buf[x+ly*dc->width_internal];; 1330 for(y=ly;y<hy;y+=4) { 1331 if(depth_b[0]>farest) { 1332 tx=mat[0]*x+mat[1]*y+mat[2]; 1333 ty=mat[3]*x+mat[4]*y+mat[5]; 1334 tz=mat[6]*x+mat[7]*y+mat[8]; 1335 tx/=tz,ty/=tz; 1336 i=GrPeek(texture, 1337 tx*texture->width, 1338 ty*texture->height 1339 ); 1340 if(0<=i<=15) { 1341 i=gr.to_8_colors[i]; 1342 if(force_color) i=force_color; 1343 dst[0](U32)=i; 1344 depth_b[0](U64)=idist; 1345 depth_b[2](U64)=idist; 1346 dst+=dc->width_internal; 1347 depth_b+=dc->width_internal; 1348 1349 dst[0](U32)=i; 1350 depth_b[0](U64)=idist; 1351 depth_b[2](U64)=idist; 1352 dst+=dc->width_internal; 1353 depth_b+=dc->width_internal; 1354 1355 dst[0](U32)=i; 1356 depth_b[0](U64)=idist; 1357 depth_b[2](U64)=idist; 1358 dst+=dc->width_internal; 1359 depth_b+=dc->width_internal; 1360 1361 dst[0](U32)=i; 1362 depth_b[0](U64)=idist; 1363 depth_b[2](U64)=idist; 1364 dst+=dc->width_internal; 1365 depth_b+=dc->width_internal; 1366 1367 if(GR_HEIGHT/2/4==y/4) 1368 if(GR_WIDTH/2/4==x/4) { 1369 hit=TRUE; 1370 } 1371 } else { 1372 skip:; 1373 dst+=dc->width_internal*4; 1374 depth_b+=dc->width_internal*4; 1375 } 1376 } else 1377 goto skip; 1378 } 1379 } 1380 return hit; 1381 } 1382 1383 1384 Bool IsLeftSide(CD2 *a,CD2 *b,CD2 *c) { 1385 return (b->x-a->x)*(c->y-a->y)-(b->y-a->y)*(c->x-a->x)>=0.; 1386 } 1387 1388 U0 DrawBlock(C3DWorldManager *man,I64 x,I64 y,I64 z) { 1389 C3DWorld *w=man->world_handle; 1390 I64 b=BlockAtXYZ(x,y,z),s; 1391 CDC *t; 1392 if(b==-1||!b) 1393 return ; 1394 CD3 points[4]; 1395 x*=128; 1396 y*=128; 1397 if(t=w->floor_textures[b]) { 1398 points[0].x=x; 1399 points[0].y=y; 1400 points[0].z=z; 1401 points[1].x=x+128; 1402 points[1].y=y; 1403 points[1].z=z; 1404 points[2].x=x+128; 1405 points[2].y=y+128; 1406 points[2].z=z; 1407 points[3].x=x; 1408 points[3].y=y+128; 1409 points[3].z=z; 1410 if(!BlockAtXYZ(x/128,y/128,z+1)) 1411 if(DrawQuad(w,t,&points)) { 1412 man->cur_tile_x=x/128; 1413 man->cur_tile_y=y/128; 1414 man->cur_tile_z=z; 1415 man->cur_tile_side_x=0; 1416 man->cur_tile_side_y=0; 1417 man->cur_tile_side_z=1; 1418 } 1419 } 1420 if(t=w->ceil_textures[b]) { 1421 points[0].x=x; 1422 points[0].y=y; 1423 points[0].z=z-1; 1424 points[1].x=x+128; 1425 points[1].y=y; 1426 points[1].z=z-1; 1427 points[2].x=x+128; 1428 points[2].y=y+128; 1429 points[2].z=z-1; 1430 points[3].x=x; 1431 points[3].y=y+128; 1432 points[3].z=z-1; 1433 if(!BlockAtXYZ(x/128,y/128,z-1)) 1434 if(DrawQuad(w,t,&points)) { 1435 man->cur_tile_x=x/128; 1436 man->cur_tile_y=y/128; 1437 man->cur_tile_z=z; 1438 man->cur_tile_side_x=0; 1439 man->cur_tile_side_y=0; 1440 man->cur_tile_side_z=-1; 1441 } 1442 } 1443 if(t=w->wall_textures[b]) { 1444 points[0].z=z; 1445 points[1].z=z; 1446 points[2].z=z-1; 1447 points[3].z=z-1; 1448 1449 points[0].x=x; 1450 points[0].y=y; 1451 points[1].x=x+128; 1452 points[1].y=y; 1453 points[2].x=x+128; 1454 points[2].y=y; 1455 points[3].x=x; 1456 points[3].y=y; 1457 if(!IsLeftSide(&points[0],&points[1],&w->x)) 1458 if(!BlockAtXYZ(x/128,y/128-1,z)) 1459 if(DrawQuad(w,t,&points)) { 1460 man->cur_tile_x=x/128; 1461 man->cur_tile_y=y/128; 1462 man->cur_tile_z=z; 1463 man->cur_tile_side_x=0; 1464 man->cur_tile_side_y=-1; 1465 man->cur_tile_side_z=0; 1466 } 1467 points[0].x=x; 1468 points[0].y=y; 1469 points[1].x=x; 1470 points[1].y=y+128; 1471 points[2].x=x; 1472 points[2].y=y+128; 1473 points[3].x=x; 1474 points[3].y=y; 1475 if(!IsLeftSide(&points[1],&points[0],&w->x)) 1476 if(!BlockAtXYZ(x/128-1,y/128,z)) 1477 if(DrawQuad(w,t,&points)) { 1478 man->cur_tile_x=x/128; 1479 man->cur_tile_y=y/128; 1480 man->cur_tile_z=z; 1481 man->cur_tile_side_x=-1; 1482 man->cur_tile_side_y=0; 1483 man->cur_tile_side_z=0; 1484 } 1485 points[0].x=x+128; 1486 points[0].y=y+128; 1487 points[1].x=x; 1488 points[1].y=y+128; 1489 points[2].x=x; 1490 points[2].y=y+128; 1491 points[3].x=x+128; 1492 points[3].y=y+128; 1493 if(!IsLeftSide(&points[0],&points[1],&w->x)) 1494 if(!BlockAtXYZ(x/128,y/128+1,z)) 1495 if(DrawQuad(w,t,&points)) { 1496 man->cur_tile_x=x/128; 1497 man->cur_tile_y=y/128; 1498 man->cur_tile_z=z; 1499 man->cur_tile_side_x=0; 1500 man->cur_tile_side_y=1; 1501 man->cur_tile_side_z=0; 1502 } 1503 1504 points[0].x=x+128; 1505 points[0].y=y+128; 1506 points[1].x=x+128; 1507 points[1].y=y; 1508 points[2].x=x+128; 1509 points[2].y=y; 1510 points[3].x=x+128; 1511 points[3].y=y+128; 1512 if(!IsLeftSide(&points[1],&points[0],&w->x)) 1513 if(!BlockAtXYZ(x/128+1,y/128,z)) 1514 if(DrawQuad(w,t,&points)) { 1515 man->cur_tile_x=x/128; 1516 man->cur_tile_y=y/128; 1517 man->cur_tile_z=z; 1518 man->cur_tile_side_x=1; 1519 man->cur_tile_side_y=0; 1520 man->cur_tile_side_z=0; 1521 } 1522 } 1523 } 1524 1525 F64 NormalizeAngle(F64 a) { 1526 a%=2*pi; 1527 if(a<0) a+=2*pi; 1528 return a; 1529 } 1530 1531 1532 Bool ClipLineToCamera(C3DWorld *w,CD3 *a,CD3 *b) { 1533 CD2 cam,left,right; 1534 CD2 dst; 1535 CD3 oa,ob; 1536 F64 a_angle=Arg(a->x-w->x,a->y-w->y); 1537 F64 b_angle=Arg(b->x-w->x,b->y-w->y); 1538 F64 dist=Sqrt(Sqr(b->x-a->x)+Sqr(b->y-a->y)); 1539 Bool in_view=FALSE; 1540 oa.x=a->x; 1541 oa.y=a->y; 1542 oa.z=a->z; 1543 ob.x=b->x; 1544 ob.y=b->y; 1545 ob.z=b->z; 1546 cam.x=w->x; 1547 cam.y=w->y; 1548 left.x=cam.x+I16_MAX*Cos(pi/2.5+w->angle); 1549 left.y=cam.y+I16_MAX*Sin(pi/2.5+w->angle); 1550 right.x=cam.x+I16_MAX*Cos(-pi/2.5+w->angle); 1551 right.y=cam.y+I16_MAX*Sin(-pi/2.5+w->angle); 1552 if(PlaneIntersect(&dst,a,b,&cam,&left)) { 1553 if(IsLeftSide(&cam,&left,a)) { 1554 a->z=Lerp(Sqrt(Sqr(dst.x-oa.x)+Sqr(dst.y-oa.y))/dist,oa.z,ob.z); 1555 a->x=dst.x; 1556 a->y=dst.y; 1557 } 1558 if(IsLeftSide(&cam,&left,b)){ 1559 b->x=dst.x; 1560 b->y=dst.y; 1561 b->z=Lerp(Sqrt(Sqr(dst.x-oa.x)+Sqr(dst.y-oa.y))/dist,oa.z,ob.z); 1562 } 1563 in_view=TRUE; 1564 } 1565 if(PlaneIntersect(&dst,a,b,&cam,&right)) { 1566 if(!IsLeftSide(&cam,&right,a)) { 1567 a->x=dst.x; 1568 a->y=dst.y; 1569 a->z=Lerp(Sqrt(Sqr(dst.x-oa.x)+Sqr(dst.y-oa.y))/dist,oa.z,ob.z); 1570 } 1571 if(!IsLeftSide(&cam,&right,b)){ 1572 b->x=dst.x; 1573 b->y=dst.y; 1574 b->z=Lerp(Sqrt(Sqr(dst.x-oa.x)+Sqr(dst.y-oa.y))/dist,oa.z,ob.z); 1575 } 1576 in_view=TRUE; 1577 } 1578 if(in_view) return TRUE; 1579 if(Cos(a_angle-w->angle)<0&&Cos(b_angle-w->angle)<0) 1580 return FALSE; 1581 return TRUE; 1582 // return in_view||!IsLeftSide(&cam,&left,a)||!IsLeftSide(&cam,&left,b) 1583 // ||IsLeftSide(&cam,&right,a)||IsLeftSide(&cam,&right,b); 1584 } 1585 1586 1587 //Also prepares CWallStain's 1588 U0 PrepareThingsForDraw(C3DWorldManager *wm,F64 thing_scale=.6) { 1589 I64 args[3]; 1590 args[0]=FrogNumNew(w->x),args[1]=FrogNumNew(w->y),args[2]=FrogNumNew(VIEW_DIST*128); 1591 CFrogArray *arr=WorldManagerThingsInRadius(wm,args,3); 1592 C3DThing **things=arr->items->body,*thing; 1593 CWallStain **stains,*stain; 1594 I64 cnt=arr->items->cnt,ix,iy,ox,oy,idx; 1595 Bool visible; 1596 F64 normal; 1597 CDC *hit_texture,*to_dc=w->to_dc; 1598 CD3 scrn_st,scrn_en; 1599 CD3 scrn_corners[4]; 1600 I64 mnx,mxx,mny,mxy; 1601 CD3 clip_st,clip_en; 1602 U32 *dst_ptr; 1603 U64 *dst_db_ptr; 1604 F64 xx,yy,matrix[9],zz,matrix2[9]; 1605 F64 width; 1606 F64 st,en; 1607 F64 stz,enz; 1608 U32 dist; 1609 w->things_around_camera_origin_x=Floor(w->x/128.)-VIEW_DIST; 1610 w->things_around_camera_origin_y=Floor(w->y/128.)-VIEW_DIST; 1611 while(--cnt>=0) { 1612 thing=things[cnt]; 1613 if(thing->no_draw) 1614 goto skip; 1615 hit_texture=ThingFace(wm->world_handle,thing,&thing->draw_flip); 1616 if(!hit_texture) 1617 goto skip; 1618 thing->draw_face=hit_texture; 1619 normal=Arg(w->x-thing->x,w->y-thing->y)-pi/2; 1620 scrn_st.x=thing->x-hit_texture->width/2.*Cos(normal)*thing_scale; 1621 scrn_st.y=thing->y-hit_texture->width/2.*Sin(normal)*thing_scale; 1622 scrn_en.x=scrn_st.x+hit_texture->width*Cos(normal)*thing_scale; 1623 scrn_en.y=scrn_st.y+hit_texture->width*Sin(normal)*thing_scale; 1624 scrn_st.z=0; 1625 scrn_en.z=0; 1626 1627 D3Copy(&clip_st,&scrn_st); 1628 D3Copy(&clip_en,&scrn_en); 1629 if(!ClipLineToCamera(w,&clip_st,&clip_en)) { 1630 goto skip; 1631 } 1632 1633 visible=FALSE; 1634 visible|=PointToScrn(w,clip_st.x,clip_st.y,thing->z+hit_texture->height/128.*thing_scale,&scrn_corners[0]); 1635 visible|=PointToScrn(w,clip_st.x,clip_st.y,thing->z,&scrn_corners[1]); 1636 visible|=PointToScrn(w,clip_en.x,clip_en.y,thing->z,&scrn_corners[2]); 1637 visible|=PointToScrn(w,clip_en.x,clip_en.y,thing->z+hit_texture->height/128.*thing_scale,&scrn_corners[3]); 1638 if(visible) { 1639 st=0; 1640 en=1.; 1641 1642 //If we clipped the line,compute the new start and end 1643 st=Sqrt(Sqr(scrn_st.y-clip_st.y)+Sqr(scrn_st.x-clip_st.x))/(hit_texture->width*thing_scale); 1644 en=Sqrt(Sqr(scrn_st.y-clip_en.y)+Sqr(scrn_st.x-clip_en.x))/(hit_texture->width*thing_scale); 1645 1646 stz=Sqrt(Sqr(w->x-clip_st.x)+Sqr(w->y-clip_st.y)); 1647 enz=Sqrt(Sqr(w->x-clip_en.x)+Sqr(w->y-clip_en.y)); 1648 1649 PointsToMat(scrn_corners,matrix); 1650 MemCpy(matrix2,matrix,8*9); 1651 Mat3x3Inv(matrix); 1652 mnx=GR_WIDTH; 1653 mxx=0; 1654 mny=GR_HEIGHT; 1655 mxy=0; 1656 for(idx=0;idx!=4;idx++) { 1657 mnx=MinI64(mnx,scrn_corners[idx].x); 1658 mxx=MaxI64(mxx,scrn_corners[idx].x); 1659 mny=MinI64(mny,scrn_corners[idx].y); 1660 mxy=MaxI64(mxy,scrn_corners[idx].y); 1661 } 1662 mnx=ClampI64(mnx,0,GR_WIDTH)&~3; 1663 mxx=ClampI64(mxx,0,GR_WIDTH)&~3; 1664 mny=ClampI64(mny,0,GR_HEIGHT)&~3; 1665 mxy=ClampI64(mxy,0,GR_HEIGHT)&~3; 1666 for(ix=mnx;ix<mxx;ix+=4) { 1667 dst_ptr=&to_dc->body[ix+mny*to_dc->width_internal]; 1668 dst_db_ptr=&to_dc->depth_buf[ix+mny*to_dc->width_internal]; 1669 for(iy=mny;iy<mxy;iy+=4) { 1670 xx=matrix[0]*ix+matrix[1]*iy+matrix[2]; 1671 yy=matrix[3+0]*ix+matrix[3+1]*iy+matrix[3+2]; 1672 zz=matrix[6+0]*ix+matrix[6+1]*iy+matrix[6+2]; 1673 xx/=zz; 1674 yy/=zz; 1675 if(0.<=xx<1.) 1676 if(0.<=yy<1.) { 1677 //Account for "clipped" start/end 1678 if(thing->draw_flip) { 1679 xx=Lerp(xx,1.-st,1.-en); 1680 dist=Lerp(xx,enz,stz); 1681 } else { 1682 xx=Lerp(xx,st,en); 1683 dist=Lerp(xx,stz,enz); 1684 } 1685 to_dc->color=GrPeek(hit_texture,xx*(hit_texture->width-1),(hit_texture->height-1)*yy); 1686 if(TRANSPARENT>to_dc->color>=0) { 1687 for(idx=0;idx!=4;idx++) { 1688 if(dst_db_ptr->i32[0]>dist) { 1689 *dst_ptr=gr.to_8_colors[to_dc->color]; 1690 *dst_db_ptr=dist|dist<<32; 1691 dst_db_ptr[1]=dist|dist<<32; 1692 } 1693 dst_ptr(U8*)+=to_dc->width_internal; 1694 dst_db_ptr(I32*)+=to_dc->width_internal; 1695 } 1696 1697 goto pass; 1698 } 1699 } 1700 dst_ptr(U8*)+=4*to_dc->width_internal; 1701 dst_db_ptr(I32*)+=4*to_dc->width_internal; 1702 pass:; 1703 } 1704 } 1705 } 1706 skip:; 1707 } 1708 1709 //Stains 1710 for(ox=0;ox!=2*VIEW_DIST;ox++) 1711 for(oy=0;oy!=2*VIEW_DIST;oy++) { 1712 if(!w->stains_around_camera[ox][oy]) 1713 w->stains_around_camera[ox][oy]=I64SetNew; 1714 else 1715 w->stains_around_camera[ox][oy]->cnt=0; 1716 } 1717 1718 stains=wm->wall_stains->items->body; 1719 cnt=wm->wall_stains->items->cnt; 1720 while(--cnt>=0) { 1721 stain=stains[cnt]; 1722 ix=stain->tile_x-w->things_around_camera_origin_x; 1723 iy=stain->tile_y-w->things_around_camera_origin_y; 1724 if(0<=ix<2*VIEW_DIST) 1725 if(0<=iy<2*VIEW_DIST) 1726 I64SetAdd(w->stains_around_camera[ix][iy],stain); 1727 } 1728 } 1729 I64 ToTile(I64 block) { 1730 return block/256; 1731 } 1732 1733 //https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection 1734 #ifdef TARGET_X86 1735 Bool SegmentSegmentIntersect(CD2 *hit_at,CD2 *a,CD2 *b,CD2 *a2,CD2 *b2,F64 *t,F64 *u) { 1736 CD2 _a,_b,_a2,_b2,tmpb,tmpt,tmpu; 1737 _a.x=a->x; 1738 _a.y=a->y; 1739 _b.x=b->x; 1740 _b.y=b->y; 1741 _a2.x=a2->x; 1742 _a2.y=a2->y; 1743 _b2.x=b2->x; 1744 _b2.y=b2->y; 1745 MOVUPD XMM3,&_a[RBP]; 1746 MOVUPD XMM4,&_b[RBP]; 1747 MOVUPD XMM5,&_a2[RBP]; 1748 MOVUPD XMM1,&_b2[RBP]; 1749 1750 1751 MOVUPD XMM0,XMM3; 1752 SUBPD XMM0,XMM4 //a-b 1753 MOVUPD XMM2,XMM5 1754 SUBPD XMM2,XMM1 //a2-b2 1755 //xx 1756 MOVSD2 &tmpb+8[RBP],XMM0 1757 MOVSD2 &tmpb[RBP],XMM2 1758 //yy 1759 SHUFPD XMM0,XMM2,0b11 1760 MOVUPD XMM2,&tmpb[RBP] 1761 MULPD XMM2,XMM0 1762 MOVUPD &tmpb[RBP],XMM2 1763 1764 MOVUPD XMM2,XMM5 1765 SUBPD XMM2,XMM1 //a2-b2 1766 MOVUPD XMM0,XMM3; 1767 SUBPD XMM0,XMM5 //a-a2 1768 //xx 1769 MOVSD2 &tmpt+8[RBP],XMM0 1770 MOVSD2 &tmpt[RBP],XMM2 1771 SHUFPD XMM0,XMM2,0b11 //Move yy into XMMM0 1772 MOVUPD XMM2,&tmpt[RBP] 1773 MULPD XMM2,XMM0 1774 MOVUPD &tmpt[RBP],XMM2 1775 1776 1777 MOVUPD XMM2,XMM3; 1778 SUBPD XMM2,XMM5 //a-a2 1779 MOVUPD XMM0,XMM3; 1780 SUBPD XMM0,XMM4 //a-b 1781 //xx 1782 MOVSD2 &tmpu+8[RBP],XMM0 1783 MOVSD2 &tmpu[RBP],XMM2 1784 SHUFPD XMM0,XMM2,0b11 //Move yy into XMMM0 1785 MOVUPD XMM2,&tmpu[RBP] 1786 MULPD XMM2,XMM0 1787 MOVUPD &tmpu[RBP],XMM2 1788 1789 //Do these after the asm blob to avoid messing up tmp registers 1790 F64 bottom=tmpb.y-tmpb.x; 1791 F64 _t=(tmpt.y-tmpt.x)/bottom; 1792 F64 _u=-(tmpu.y-tmpu.x)/bottom; 1793 1794 if(0<=_t<=1) 1795 if(0<=_u<=1) { 1796 if(t) *t=_t; 1797 if(u) *u=_u; 1798 if(hit_at) { 1799 hit_at->x=a->x+_t*(b->x-a->x); 1800 hit_at->y=a->y+_t*(b->y-a->y); 1801 } 1802 return TRUE; 1803 } 1804 return FALSE; 1805 } 1806 #else 1807 Bool SegmentSegmentIntersect(CD2 *hit_at,CD2 *a,CD2 *b,CD2 *a2,CD2 *b2,F64 *t,F64 *u) { 1808 F64 bottom=(a->x-b->x)*(a2->y-b2->y)-(a->y-b->y)*(a2->x-b2->x); 1809 F64 _t=((a->x-a2->x)*(a2->y-b2->y)-(a->y-a2->y)*(a2->x-b2->x))/bottom; 1810 F64 _u=-((a->x-b->x)*(a->y-a2->y)-(a->y-b->y)*(a->x-a2->x))/bottom; 1811 if(0<=_t<=1) 1812 if(0<=_u<=1) { 1813 if(t) *t=_t; 1814 if(u) *u=_u; 1815 if(hit_at) { 1816 hit_at->x=a->x+_t*(b->x-a->x); 1817 hit_at->y=a->y+_t*(b->y-a->y); 1818 } 1819 return TRUE; 1820 } 1821 return FALSE; 1822 } 1823 #endif 1824 //https://github.com/cgyurgyik/fast-voxel-traversal-algorithm/blob/master/overview/FastVoxelTraversalOverview.md 1825 #define RAY_TRACE_MAX_DEPTH 3 1826 I64 BlockHitColor(CD3 *at,CD3 *ray,I64 x,I64 y,I64 z,I64 sidex,I64 sidey,I64 sidez,CD3 *hit_at=NULL,F64 *hit_d=NULL,CD2I64 *texture_cords=NULL) { 1827 CD3 pos,dst; 1828 CDC *texture=NULL; 1829 I64 b=BlockAtXYZ(x,y,z),tx,ty; 1830 pos.x=x; 1831 pos.y=y; 1832 pos.z=z; 1833 if(sidex>0) { 1834 pos.x=x+1; 1835 } 1836 else if(sidex<0) { 1837 pos.x=x; 1838 } 1839 1840 else if(sidey>0) { 1841 pos.y=y+1; 1842 } 1843 else if(sidey<0) { 1844 pos.y=y; 1845 } 1846 else if(sidez>0) { 1847 pos.z=z+1; 1848 } 1849 else if(sidez<0) { 1850 pos.z=z; 1851 } else 1852 return LTPURPLE; 1853 F64 d; 1854 if(sidez>0) { 1855 texture=w->floor_textures[b]; 1856 zstyle: 1857 d=(pos.z-at->z)/ray->z; 1858 D3Mul(&dst,d,ray); 1859 D3AddEqu(&dst,at); 1860 tx=dst.x*128; 1861 ty=dst.y*128; 1862 ty=ty&127; 1863 } else if(sidez<0) { 1864 texture=w->ceil_textures[b]; 1865 goto zstyle; 1866 } else if(sidex) { 1867 texture=w->wall_textures[b]; 1868 d=(pos.x-at->x)/ray->x; 1869 D3Mul(&dst,d,ray); 1870 D3AddEqu(&dst,at); 1871 tx=dst.y*128; 1872 ty=dst.z*128; 1873 ty=127-ty&127; 1874 } else if(sidey) { 1875 texture=w->wall_textures[b]; 1876 d=(pos.y-at->y)/ray->y; 1877 D3Mul(&dst,d,ray); 1878 D3AddEqu(&dst,at); 1879 tx=dst.x*128; 1880 ty=dst.z*128; 1881 ty=127-ty&127; 1882 } 1883 if(hit_d) 1884 *hit_d=Sqrt(Sqr(dst.z-at->z)+Sqr(dst.y-at->y)+Sqr(dst.x-at->x)); 1885 if(hit_at) 1886 D3Equ(hit_at,dst.x*128,dst.y*128,dst.z); 1887 if(texture_cords) { 1888 texture_cords->x=tx&127; 1889 if(sidez) 1890 texture_cords->y=ty&127; 1891 else 1892 texture_cords->y=127-ty; 1893 } 1894 if(texture) 1895 return GrPeek(texture,tx&127,ty&127); 1896 return BLACK; 1897 } 1898 I64 GetColorForRay(C3DWorldManager *man,CD3 *origin,CD3 *ray,F64 dist,F64 *hit_at,CD3 *hit_cords,I64 depth=0,I64 last_block=0,I64 fog_color=BLACK,Bool record_tile=FALSE) { 1899 CFrogArray *grid=man->grid; 1900 C3DWorld *w=man->world_handle; 1901 CI64Set *do_things; 1902 F64 x=origin->x/128,y=origin->y/128; 1903 CDoor *door; 1904 Bool hit=FALSE; 1905 F64 hit_dist=1e100; 1906 CWallStain **wall_stains,*wall_stain; 1907 I64 wall_stain_cnt; 1908 I64 hit_color=-1; 1909 I64 tx=x,ty=y,idx,tz; 1910 I64 cnt=dist/128.; 1911 I64 stepx=Sign(ray->z); 1912 I64 stepy=Sign(-ray->x); 1913 I64 stepz=Sign(-ray->y); 1914 if(-.001<=Ceil(x)-x<=.001) x-=.001; 1915 if(-.001<=Ceil(y)-y<=.001) y-=.001; 1916 if(-.001<=Ceil(origin->z)-origin->z<=.001) origin->z-=.001; 1917 F64 current_x_index=Ceil(x); 1918 F64 current_y_index=Ceil(y); 1919 F64 current_z_index=Ceil(origin->z); 1920 if(stepx<0) current_x_index--; 1921 if(stepy<0) current_y_index--; 1922 if(stepz<0) current_z_index--; 1923 F64 tMaxX=(current_x_index-x)/ray->z; 1924 F64 tMaxY=(current_y_index-y)/-ray->x; 1925 F64 tMaxZ=(current_z_index-origin->z)/-ray->y; 1926 F64 h,h2; 1927 F64 angle=Arg(ray->z,-ray->x); 1928 F64 cos=Cos(angle),sin=Sin(angle); 1929 F64 slope=-ray->y/Sqrt(Sqr(ray->z)+Sqr(ray->x)); //??? 1930 F64 r_abs_rx=1./Abs(ray->x); 1931 F64 r_abs_ry=1./Abs(ray->y); 1932 F64 r_abs_rz=1./Abs(ray->z); 1933 CDC *hit_texture; 1934 CDC *stain_dc; 1935 I64 cur,thing_idx,texture_x,texture_y; 1936 I64 wall_side; 1937 I64 stain_x,stain_y; 1938 I64 color; 1939 I64 relx,rely; 1940 F64 lighting; 1941 CD2 long,long128,xyhit,origin_d_128; 1942 I64 side; 1943 CD2I64 texture_cords; 1944 I64 sidex=0,sidey=0,sidez=0; 1945 CD3 o128,rp; 1946 rp.x=ray->z; 1947 rp.y=-ray->x; 1948 rp.z=-ray->y; 1949 o128.x=origin->x/128; 1950 o128.y=origin->y/128; 1951 o128.z=origin->z; 1952 long.x=x+VIEW_DIST*cos; 1953 long.y=y+VIEW_DIST*sin; 1954 long128.x=long.x*128; 1955 long128.y=long.y*128; 1956 tx=x; 1957 ty=y; 1958 tz=Floor(origin->z); 1959 for(cur=0;cur!=cnt&&!hit;cur++) { 1960 if(I8_MIN<=tz<I8_MAX) 1961 if(0<=tx<w->world_width) 1962 if(0<=ty<w->world_height) { 1963 idx=ty*w->world_width+tx; 1964 lighting=ClampI64(w->world_lighting[idx*256+tz-I8_MIN],0,15); 1965 relx=tx-w->things_around_camera_origin_x; 1966 rely=ty-w->things_around_camera_origin_y; 1967 idx=(ty*w->world_width+tx)*256+tz-I8_MIN; 1968 if(w->world_blocks[idx]) { 1969 if(w->world_blocks[idx]==last_block) goto pass; 1970 tile:; 1971 CD3 new_origin; 1972 CD3 new_ray; 1973 idx=(ty*w->world_width+tx)*256+tz-I8_MIN; 1974 idx=w->world_blocks[idx]; 1975 if(record_tile) { 1976 man->cur_tile_x=tx; 1977 man->cur_tile_y=ty; 1978 man->cur_tile_z=tz; 1979 man->cur_tile_side_x=sidex; 1980 man->cur_tile_side_y=sidey; 1981 man->cur_tile_side_z=sidez; 1982 } 1983 color=BlockHitColor(&o128,&rp,tx,ty,tz,sidex,sidey,sidez,&new_origin,&hit_dist,&texture_cords); 1984 if(0<=relx<2*VIEW_DIST) 1985 if(0<=rely<2*VIEW_DIST) 1986 if(cnt=(do_things=w->stains_around_camera[relx][rely])->cnt) 1987 goto try_stains; 1988 goto try_block; 1989 try_stains:; 1990 wall_stains=do_things->body; 1991 wall_stain_cnt=cnt; 1992 while(--wall_stain_cnt>=0) { 1993 wall_stain=wall_stains[wall_stain_cnt]; 1994 if((sidex&&wall_stain->sidex==sidex)||(sidey&&wall_stain->sidey==sidey)||(sidez&&wall_stain->sidez==sidez)) 1995 if(wall_stain->tile_x==tx&&wall_stain->tile_y==ty&&wall_stain->tile_z==tz) { 1996 if(0<=GrPeek(wall_stain->dc, 1997 (texture_cords.x&127), 1998 (texture_cords.y&127) 1999 )<TRANSPARENT) { 2000 color=GrPeek(wall_stain->dc,texture_cords.x&127,texture_cords.y&127); 2001 goto valid_color; 2002 } 2003 2004 } 2005 } 2006 try_block:; 2007 //For-recursive 2008 if(0&&IsLiquidTile(idx)&&depth<RAY_TRACE_MAX_DEPTH) { 2009 //TODO displace ray based on "wavew" 2010 fog_color=color&0xff; 2011 depth++; 2012 last_block=idx; 2013 //Weird issues with exact values 2014 //Snells law 2015 F64 snell_a,snell_a2,normal; 2016 F64 t=Frog_tS/30.; 2017 F64 rand_refrac=1.1+.1*(Abs(Sin((t/4.)*200))-Abs(Cos(t*125)))+.1*(Rand-.5)*2; 2018 if(!sidez) { 2019 normal=(1+side)*pi/2; 2020 snell_a=Arg(origin->x-xyhit.x*128,origin->y-xyhit.y*128)-normal; 2021 snell_a=ASin(Sin(snell_a)/rand_refrac); 2022 snell_a=normal-snell_a+pi; 2023 new_ray.x=Sin(snell_a); 2024 new_ray.y=ray->y*ASin(Sin((pi/2-ATan(slope)))/(rand_refrac+.2)); 2025 new_ray.z=-Cos(snell_a); 2026 } else { 2027 if(slope<0.) 2028 normal=pi/2; 2029 else 2030 normal=-pi/2; 2031 snell_a=ATan(slope)-normal; 2032 snell_a=ASin(Sin(snell_a)/rand_refrac); 2033 snell_a=normal-snell_a+pi; 2034 new_ray.x=ray->x; 2035 new_ray.y=-Sin(snell_a); 2036 new_ray.z=ray->z; 2037 } 2038 return GetColorForRay(man,&new_origin,&new_ray,128*VIEW_DIST,hit_at,hit_cords,depth,last_block,fog_color); 2039 } 2040 valid_color: 2041 if(hit_cords) { 2042 D3Copy(hit_cords,&new_origin); 2043 } 2044 hit_dist*=128; 2045 if(hit_at) *hit_at=hit_dist; 2046 hit=TRUE; 2047 F64 ao_nodes[4]; 2048 F64 adj_lights[4]; 2049 F64 ao; 2050 for(idx=0;idx!=4;idx++) 2051 ao_nodes[idx]=BlockAO(idx,tx,ty,tz,sidex,sidey,sidez); 2052 for(idx=0;idx!=4;idx++) 2053 adj_lights[idx]=CornerLight(idx,tx,ty,tz,sidex,sidey,sidez); 2054 F64 u0=texture_cords.x/127.; 2055 F64 u1=1-texture_cords.x/127.; 2056 F64 v0=texture_cords.y/127.; 2057 F64 v1=1-texture_cords.y/127.; 2058 //Bilnear 2059 ao=.5; 2060 ao+=ao_nodes[3] *v1*u1; 2061 ao+=ao_nodes[2] *u0*v1; 2062 ao+=ao_nodes[0] *u1*v0; 2063 ao+=ao_nodes[1] *u0*v0; 2064 lighting=LightAtXYZ(tx+sidex,ty+sidey,tz+sidez); 2065 lighting-=3-ao; 2066 lighting=(Lerp(u0,adj_lights[0],adj_lights[2])+Lerp(v0,adj_lights[1],adj_lights[3])+lighting)/3.; 2067 hit_color=Fog(color,hit_dist+1+depth*FOG_DIST*4+MaxI64((15-lighting)*FOG_DIST,0),fog_color); 2068 } 2069 goto pass; 2070 } 2071 break; 2072 pass:; 2073 sidex=sidey=sidez=0; 2074 if(tMaxX<tMaxY) { 2075 if(tMaxX<tMaxZ) { 2076 tMaxX+=r_abs_rz; 2077 tx+=stepx; 2078 sidex=-stepx; 2079 } else { 2080 tMaxZ+=r_abs_ry; 2081 tz+=stepz; 2082 sidez=-stepz; 2083 } 2084 } else { 2085 if(tMaxY<tMaxZ) { 2086 tMaxY+=r_abs_rx; 2087 ty+=stepy; 2088 sidey=-stepy; 2089 } else { 2090 tMaxZ+=r_abs_ry; 2091 tz+=stepz; 2092 sidez=-stepz; 2093 } 2094 } 2095 } 2096 fin: 2097 if(depth&&!hit) { 2098 return gr.to_8_colors[fog_color&0xff]; 2099 } 2100 return hit_color; 2101 } 2102 2103 I64 mp_done=0; 2104 2105 //https://blog.scottlogic.com/2020/03/10/raytracer-how-to.html 2106 //ca==Cos(-w->angle) 2107 //sa==Sin(-w->angle) 2108 //ca2==Cos(-w->angle2) 2109 //sa2==Sin(-w->angle2) 2110 U0 GenerateRay(C3DWorld *world,CD2 *ray_look,F64 i,F64 j,F64 width,F64 height,F64 ca,F64 sa,F64 ca2,F64 sa2) { 2111 CD3 m,tmpy,tmpx; 2112 D3Equ(&m,(i/width-.5)*-2,(j/height-.5)*2,1); 2113 D3Equ(&tmpy, 2114 m.x, 2115 m.y*ca2-m.z*sa2, 2116 m.y*sa2+m.z*ca2 2117 ); 2118 D3Equ(ray_look, 2119 tmpy.x*ca+tmpy.z*sa, 2120 tmpy.y, 2121 -tmpy.x*sa+tmpy.z*ca, 2122 ); 2123 D3Norm(ray_look); 2124 } 2125 2126 2127 U0 MPCastCol(C3DWorldManager *wm) { 2128 C3DWorld *w=wm->world_handle; 2129 F64 angle=w->angle-w->fov/2,angle2,hit_dist,ath; 2130 F64 dist,dist2,h,h2; 2131 F64 sin,width=GR_WIDTH,cos1,sin1,tan1,cos12; 2132 I64 cap,idx,x,y; 2133 CDoor *door; 2134 CDC *to_dc=w->to_dc; 2135 CDC *what; 2136 CD3 *p; 2137 I64 *tiles,tile; 2138 I64 color,col; 2139 U32 *ptr; 2140 I32 *depth_ptr; 2141 I64 tx,ty; 2142 I64 segment; 2143 I64 idist,row; 2144 Bool hit_wall; 2145 Bool record_tile=FALSE; 2146 I64 fogc; 2147 CD3 ray; 2148 F64 angle_offset_table[GR_WIDTH]; 2149 F64 y_angle_offset_table[GR_HEIGHT]; 2150 F64 xrot=w->angle2; 2151 F64 sa=Sin(-w->angle); 2152 F64 ca=Cos(-w->angle); 2153 F64 sa2=Sin(-w->angle2); 2154 F64 ca2=Cos(-w->angle2); 2155 Bool in_water=FALSE; 2156 F64 t=Frog_tS/30.,rand_refrac,snell_a,snell_a2; 2157 if(IsLiquidTile(BlockAtXYZ(w->x/128.,w->y/128.,Floor(w->cam_height)))) { 2158 in_water=TRUE; 2159 } 2160 idx=ToF64(Gs->num)/ToF64(mp_cnt)*GR_WIDTH; 2161 cap=ToF64(Gs->num+1)/ToF64(mp_cnt)*GR_WIDTH; 2162 for(x=idx;x<cap;x+=w->step_width) { 2163 // divide by cos2_lookup_table to get 32 blocks from the camera 2164 <1>; 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 ptr=&to_dc->body[x]; 2185 depth_ptr=&to_dc->depth_buf[x]; 2186 for(y=0;y<GR_HEIGHT;y+=w->step_width) { 2187 //Nroot has no idea what he was doing here.Literaly typing random stuff 2188 GenerateRay(w,&ray,x,y,GR_WIDTH,GR_HEIGHT,ca,sa,ca2,sa2); 2189 if(in_water) { 2190 rand_refrac=1.1+.1*(Abs(Sin((t/4.)*200))-Abs(Cos(t*125)))+.1*(Rand-.5)*2; 2191 snell_a2=(y/ToF64(GR_HEIGHT)-.5)*w->fov; 2192 snell_a=(x/ToF64(GR_WIDTH)-.5)*w->fov; 2193 snell_a=ASin(Sin(snell_a)/rand_refrac)/2.; 2194 snell_a2=ASin(Sin(snell_a2)/(rand_refrac+.2))/2.; 2195 D3Equ(&ray, 2196 ray.x*Cos(snell_a)+ray.z*Sin(snell_a), 2197 ray.y, 2198 -ray.x*Sin(snell_a)+ray.z*Cos(snell_a), 2199 ); 2200 D3Equ(&ray, 2201 ray.x, 2202 ray.y*Cos(snell_a2)-ray.z*Sin(snell_a2), 2203 ray.y*Sin(snell_a2)+ray.z*Cos(snell_a2) 2204 ); 2205 //TODO what kind of liquid are we in TOODO 2206 fogc=LTBLUE; 2207 } else 2208 fogc=BLACK; 2209 p=&w->to_point[x/4][y/4]; 2210 //If we dont hit a wall,just fill with "far out in the distacnve" 2211 p->x=w->x+ray.x*I16_MAX; 2212 p->y=w->y+ray.y*I16_MAX; 2213 p->z=w->cam_height; 2214 CD3 origin; 2215 origin.x=w->x; 2216 origin.y=w->y; 2217 origin.z=w->cam_height; 2218 //depth==1 to simulate going through a (liquid) block 2219 record_tile=FALSE; 2220 if(x/w->step_width==(GR_WIDTH/2/w->step_width)) 2221 if(y/w->step_width==(GR_HEIGHT/2/w->step_width)) { 2222 record_tile=TRUE; 2223 } 2224 2225 if(in_water) { 2226 color=GetColorForRay(wm,&origin,&ray,32*GRID_SZ,&dist,p,1*in_water,BlockAtXYZ(w->x/128.,w->y/128.,Floor(w->cam_height)),fogc,record_tile); 2227 } else 2228 color=GetColorForRay(wm,&origin,&ray,32*GRID_SZ,&dist,p,,,,record_tile); 2229 idist=dist; 2230 idist|=idist<<32; 2231 if(depth_ptr[0]<dist) { 2232 ptr(U8*)+=to_dc->width_internal*w->step_width; 2233 depth_ptr(I32*)+=to_dc->width_internal*w->step_width; 2234 goto fin; 2235 } 2236 if(color!=-1&&w->step_width==2) { 2237 for(col=0;col!=2;col++) { 2238 if(col&1) 2239 ptr(U16*)[0]=color; 2240 else 2241 ptr(U16*)[0]=color>>8; //Dither 2242 depth_ptr[0](I64)=idist; 2243 ptr(U8*)+=to_dc->width_internal; 2244 depth_ptr+=to_dc->width_internal; 2245 } 2246 goto fin; 2247 } 2248 if(color!=-1&&w->step_width==4) { 2249 for(col=0;col!=4;col++) { 2250 if(col&1) 2251 ptr(U32*)[0]=color; 2252 else 2253 ptr(U32*)[0]=color>>8; //Dither 2254 depth_ptr[0](I64)=idist; 2255 depth_ptr[2](I64)=idist; 2256 ptr(U8*)+=to_dc->width_internal; 2257 depth_ptr+=to_dc->width_internal; 2258 } 2259 goto fin; 2260 } 2261 if(color!=-1&&w->step_width==6) { 2262 for(col=0;col!=6;col++) { 2263 if(col&1) { 2264 ptr(U32*)[0]=color; 2265 ptr(U16*)[2]=color; 2266 } else { 2267 ptr(U32*)[0]=color>>8; //Dither 2268 ptr(U16*)[2]=color>>8; //Dither 2269 } 2270 depth_ptr[0](I64)=idist; 2271 depth_ptr[2](I64)=idist; 2272 depth_ptr[4](I64)=idist; 2273 ptr(U8*)+=to_dc->width_internal; 2274 depth_ptr+=to_dc->width_internal; 2275 } 2276 goto fin; 2277 } 2278 if(color!=-1&&w->step_width==8) { 2279 for(col=0;col!=8;col++) { 2280 if(col&1) 2281 ptr(U64*)[0]=color; 2282 else 2283 ptr(U64*)[0]=color>>8|color<<(64-8); //Rotate for Dither 2284 depth_ptr[0](I64)=idist; 2285 depth_ptr[2](I64)=idist; 2286 depth_ptr[4](I64)=idist; 2287 depth_ptr[6](I64)=idist; 2288 ptr(U8*)+=to_dc->width_internal; 2289 depth_ptr+=to_dc->width_internal; 2290 } 2291 goto fin; 2292 } 2293 ptr(U8*)+=to_dc->width_internal*w->step_width; 2294 depth_ptr(I32*)+=to_dc->width_internal*w->step_width; 2295 fin:; 2296 } 2297 } 2298 LBts(&mp_done,Gs->num); 2299 } 2300 U0 C3DWorldCastRays(C3DWorld *w) { 2301 I64 c; 2302 C3DWorldManager *man=FrogSymbol("world")->value; 2303 man->cur_tile_x=-1; 2304 man->cur_tile_y=-1; 2305 man->cur_tile_z=-1; 2306 lock mp_done=0; 2307 /* for(c=1;c<mp_cnt;++c) { 2308 JobQue(&MPCastCol,man,c); 2309 } 2310 MPCastCol(man); 2311 for(c=1;c<mp_cnt;++c) { 2312 while(!Bt(&mp_done,c)) 2313 __Sleep(2); 2314 }*/ 2315 I64 x=w->x/128.,y=w->y/128.,z=w->cam_height; 2316 I64 ox,oy,oz; 2317 for(oz=-16;oz<=16;oz++) { 2318 for(ox=-16;ox<=16;ox++) 2319 for(oy=-16;oy<=16;oy++) 2320 DrawBlock(man,x+ox,y+oy,z+oz); 2321 } 2322 } 2323 Bool CanSee2DThing(C3DWorld *w,C3DThing *t) { 2324 Bool ret=TRUE; 2325 F64 dist=Sqrt(Sqr(t->x-w->x)+Sqr(t->y-w->y)),near,far,interp; 2326 F64 angle=Arg(t->x-w->x,t->y-w->y); 2327 I64 *ti=GetTilesInPath(w,angle,dist),idx; 2328 I64 at_tile=ToI64(w->x/GRID_SZ)+ToI64(w->y/GRID_SZ)*w->world_width; 2329 I64 t_at_tile=ToI64(t->x/GRID_SZ)+ToI64(t->y/GRID_SZ)*w->world_width; 2330 I64 x,y,z; 2331 I64 cnt=0; 2332 for(idx=0;ti[idx]!=-1;idx++) 2333 ++cnt; 2334 for(idx=0;idx<cnt;idx++) { 2335 x=ti[idx]%w->world_width; 2336 y=ti[idx]/w->world_width; 2337 interp=Lerp(ToF64(idx)/ToF64(cnt),w->cam_height,t->z); 2338 if(BlockAtXYZ(x,y,ToI64(interp))) { 2339 //Check if we are 1 block within result "good enough" 2340 if(Abs(x-t->x/GRID_SZ)<0||Abs(y-t->y/GRID_SZ)<0 2341 ||Abs(z-t->z)<0) 2342 break; //ret==TRUE 2343 ret=FALSE; 2344 break; 2345 } 2346 } 2347 Free(ti); 2348 return ret; 2349 } 2350 #define THING_DRAW_CUTOFF GRID_SZ/2 2351 2352 2353 U0 WMPointToScreenX(C3DWorldManager *man,I64 *argv,I64 argc) { 2354 CD3 p; 2355 PointToScrn(w, 2356 AsF64(argv[0]), 2357 AsF64(argv[1]), 2358 AsF64(argv[2]), 2359 &p); 2360 return FrogNumNew(p.x); 2361 } 2362 U0 WMPointToScreenY(C3DWorldManager *man,I64 *argv,I64 argc) { 2363 CD3 p; 2364 PointToScrn(w, 2365 AsF64(argv[0]), 2366 AsF64(argv[1]), 2367 AsF64(argv[2]), 2368 &p); 2369 return FrogNumNew(p.y); 2370 } 2371 U0 WMPointToScreenZ(C3DWorldManager *man,I64 *argv,I64 argc) { 2372 CD3 p; 2373 PointToScrn(w, 2374 AsF64(argv[0]), 2375 AsF64(argv[1]), 2376 AsF64(argv[2]), 2377 &p); 2378 return FrogNumNew(p.z); 2379 } 2380 AddMethod("C3DWorldManager","pointToScreenXAtX:atY:atZ:",&WMPointToScreenX); 2381 AddMethod("C3DWorldManager","pointToScreenYAtX:atY:atZ:",&WMPointToScreenY); 2382 AddMethod("C3DWorldManager","pointToScreenZAtX:atY:atZ:",&WMPointToScreenZ); 2383 U0 DrawParticle(C3DWorld *w,C3DParticle *p) { 2384 I32 dist=Sqrt(Sqr(w->x-p->x)+Sqr(w->y-p->y)); 2385 I64 x0,y0; 2386 CD3 res; 2387 w->to_dc->color=p->color; 2388 w->to_dc->thick=(DIST_SCALE/ToF64(1+dist))/GRID_SZ*p->size; 2389 PointToScrn(w,p->x,p->y,p->z,&res); 2390 if(w->to_dc->thick>0) 2391 GrPlot3(w->to_dc,res.x,res.y,dist+1); 2392 } 2393 2394 U0 Line3D(C3DWorld *w,CDC *dc,CD3 *st,CD3 *en) { 2395 //Make sure the line isnt insanely cose the the camera. 2396 //I approximate the things based on angles,its pretty dumb. 2397 CD3 clip,clip2,res,res2; 2398 F64 angle=Arg(en->x-st->x,en->y-st->y); 2399 clip.x=st->x; 2400 clip.y=st->y; 2401 clip.z=st->z; 2402 clip2.x=en->x; 2403 clip2.y=en->y; 2404 clip2.z=en->z; 2405 2406 ClipLineToCamera(w,&clip,&clip2); 2407 2408 2409 if(1.>Sqr(clip.x-w->x)+Sqr(clip.y-w->y)) { 2410 clip.x=32*Cos(angle)+w->x; 2411 clip.y=32*Sin(angle)+w->y; 2412 } 2413 if(1.>Sqr(clip2.x-w->x)+Sqr(clip2.y-w->y)) { 2414 clip2.x=32*Cos(angle)+w->x; 2415 clip2.y=32*Sin(angle)+w->y; 2416 } 2417 2418 PointToScrn(w,clip.x,clip.y,clip.z,&res); 2419 PointToScrn(w,clip2.x,clip2.y,clip2.z,&res2); 2420 GrLine3(dc,res.x,res.y,res.z,res2.x,res2.y,res2.z); 2421 } 2422 2423 U0 WallStainDel(CWallStain *s) { 2424 if(s->dc) AnimDCDel(s->dc); 2425 Free(s); 2426 } 2427 // 2428 // SmallTalk Section 2429 // 2430 U0 FloorStainDel(CFloorStain *s) { 2431 if(s->dc) AnimDCDel(s->dc); 2432 Free(s); 2433 } 2434 2435 CFrogThing *WallStainSetGr(CWallStain *self,I64 *argv,I64 argc) { 2436 I64 x=AsF64(argv[1]),y=AsF64(argv[2]); 2437 CFrogImg *img=argv[0]; 2438 CDC *loaded; 2439 CFrogNum *ret=FrogNumNew(0); 2440 if(ThingHasClass(img,"CFrogImg")) { 2441 if(!self->dc) { 2442 self->dc=DCNew(128,128,frog_mem_task); 2443 DCFill(self->dc); 2444 } 2445 loaded=img->dc; 2446 ret=FrogNumNew(GrBlot(self->dc,x-loaded->width/2,y-loaded->height/2,loaded)); 2447 } 2448 return ret; 2449 } 2450 AddMethod("CWallStain","addGraphics:atX:atY:",&WallStainSetGr); 2451 CFrogThing *WorldManagerNewParticle(C3DWorldManager *man,I64 *argv,I64 argc) { 2452 F64 x=AsF64(argv[0]); 2453 F64 y=AsF64(argv[1]); 2454 F64 z=AsF64(argv[2])+.001; //For not hiting floor at spawn 2455 F64 spread=AsF64(argv[3]); 2456 F64 color=AsF64(argv[4]); 2457 F64 a=Rand*2*pi; 2458 NewParticle(w,color,16,x,y,z,spread*Cos(a),spread*Sin(a),man->gravity*3); 2459 return FROG_SMALL_NIL; 2460 } 2461 2462 AddMethod("C3DWorldManager","basicNewParticleAtX:atY:atZ:withSpread:withColor:",&WorldManagerNewParticle); 2463 CFrogThing *WorldManagerNewParticle2(C3DWorldManager *man,I64 *argv,I64 argc) { 2464 F64 x=AsF64(argv[0]); 2465 F64 y=AsF64(argv[1]); 2466 F64 z=AsF64(argv[2])+.001; //For not hiting floor at spawn 2467 F64 spread=AsF64(argv[3]); 2468 F64 color=AsF64(argv[4]); 2469 U8 *splat_lump=AsString(argv[5]); 2470 F64 a=Rand*2*pi; 2471 NewParticle(w,color,16,x,y,z,spread*Cos(a),spread*Sin(a),man->gravity*3,splat_lump); 2472 Free(splat_lump); 2473 return FROG_SMALL_NIL; 2474 } 2475 2476 AddMethod("C3DWorldManager","basicNewParticleAtX:atY:atZ:withSpread:withColor:withSplatLump:",&WorldManagerNewParticle2); 2477 CFrogThing *WorldManagerNewSweepSound(C3DWorldManager *man,I64 *argv,I64 argc) { 2478 if(man->sound_task) Kill(man->sound_task,FALSE); 2479 man->sound_task=Sweep( 2480 AsF64(argv[0]), 2481 AsF64(argv[1]), 2482 AsF64(argv[2])); 2483 return FROG_SMALL_NIL; 2484 } 2485 AddMethod("C3DWorldManager","sweepSoundForTime:withMin:withMax:",&WorldManagerNewSweepSound); 2486 CFrogThing *WorldManagerNewNoiseSound(C3DWorldManager *man,I64 *argv,I64 argc) { 2487 if(man->sound_task) Kill(man->sound_task,FALSE); 2488 man->sound_task=Noise( 2489 AsF64(argv[0]), 2490 AsF64(argv[1]), 2491 AsF64(argv[2])); 2492 return FROG_SMALL_NIL; 2493 } 2494 AddMethod("C3DWorldManager","noiseSoundForTime:withMin:withMax:",&WorldManagerNewNoiseSound); 2495 CFrogThing *WorldManagerGetQuestChatBot(C3DWorldManager *man,I64 *argv,I64 argc) { 2496 U8 *name=AsString(argv[0]); 2497 CEliza *e=FROG_SMALL_NIL; 2498 if(name) 2499 e=LoadQuestChatBot(name); 2500 Free(name); 2501 return e; 2502 } 2503 AddMethod("C3DWorldManager","getQuestChatBot:",&WorldManagerGetQuestChatBot); 2504 CFrogNum *WorldManagerIsLiquid(C3DWorldManager *man,I64 *argv,I64 argc) { 2505 I64 x=AsF64(argv[0]); 2506 I64 y=AsF64(argv[1]); 2507 I64 z=Floor(AsF64(argv[2])); 2508 I64 tile=(x+y*w->world_width)*256+z-I8_MIN; 2509 if(0<=tile<w->world_width*w->world_height) { 2510 return FrogNumNew(IsLiquidTile(w->world_blocks[tile])); 2511 } 2512 return FrogNumNew(0); 2513 } 2514 AddMethod("C3DWorldManager","tileIsLiquidAtX:atY:atZ:",&WorldManagerIsLiquid); 2515 2516 //Returns 1. if COLLISION,else 0 2517 CFrogThing *C3DThingMoveAtAngle(C3DThing *self,I64 *argv,I64 argc) { 2518 CFrogThing *dist=argv[0]; 2519 CFrogThing *angle=argv[1]; 2520 Bool hit_wall=FALSE; 2521 // 2522 // 2523 //Heres the deal,world update gets ran 10 fps,but physics is 30 fps 2524 //I will "dumb" walk into a wall then set the momentum to "walk" 2525 // 2526 // 2527 F64 old_x=self->x; 2528 F64 old_y=self->y; 2529 hit_wall=C3DWorldMoveWithCollision(w,AsF64(angle),AsF64(dist),&self->x,&self->y,TRUE,self->z); 2530 self->x=old_x; 2531 self->y=old_y; 2532 self->momx2+=AsF64(dist)*Cos(AsF64(angle)); 2533 self->momy2+=AsF64(dist)*Sin(AsF64(angle)); 2534 return FrogNumNew(hit_wall); 2535 } 2536 AddMethod("C3DThing","move:atAngle:",&C3DThingMoveAtAngle); 2537 2538 CFrogThing *WorldManagerWidth(C3DWorldManager *self,I64 *argv,I64 argc) { 2539 return FrogNumNew(w->world_width); 2540 } 2541 CFrogThing *WorldManagerHeight(C3DWorldManager *self,I64 *argv,I64 argc) { 2542 return FrogNumNew(w->world_height); 2543 } 2544 2545 AddMethod("C3DWorldManager","width",&WorldManagerWidth); 2546 AddMethod("C3DWorldManager","height",&WorldManagerHeight); 2547 CFrogThing *WorldManagerSetTileAtXAtY(C3DWorldManager *self,I64 *argv,I64 argc) { 2548 I8 tile=AsF64(argv[0]); 2549 I64 x=AsF64(argv[1]); 2550 I64 y=AsF64(argv[2]); 2551 I64 z=AsF64(argv[3]); 2552 if(0<=x<w->world_width) 2553 if(0<=y<w->world_height) { 2554 if(I8_MIN<=z<I8_MAX) 2555 return w->world_blocks[(x+y*w->world_width)*256+z-I8_MIN]=tile; 2556 } 2557 return FROG_SMALL_NIL; 2558 } 2559 AddMethod("C3DWorldManager","setTile:atX:atY:atZ:",&WorldManagerSetTileAtXAtY); 2560 2561 2562 CFrogThing *ThingCanSeeThing(C3DThing *self,I64 *argv,I64 argc) { 2563 F64 old_x=w->x,old_y=w->y,old_z=w->cam_height; 2564 CFrogThing *ret; 2565 C3DThing *other=argv[0]; 2566 if(!ThingHasClass(other,"C3DThing")) 2567 return FROG_SMALL_NIL; 2568 w->x=self->x; 2569 w->y=self->y; 2570 //TODO replace "+1" with thing height 2571 w->cam_height=self->z+1.; 2572 ret=FrogNumNew(CanSee2DThing(w,other)); 2573 w->x=old_x; 2574 w->y=old_y; 2575 w->cam_height=old_z; 2576 return ret; 2577 } 2578 AddMethod("C3DThing","canSeeThing:",&ThingCanSeeThing); 2579 2580 2581 CFrogThing *ScreenCoordToDist(C3DWorldManager *self,I64 *argv,I64 argc) { 2582 CD3 *p=&w->to_point[GR_WIDTH/2/4][GR_HEIGHT/2/4]; 2583 return FrogNumNew(Sqrt(Sqr(p->x-w->x)+Sqr(p->y-w->y))); 2584 } 2585 AddMethod("C3DWorldManager","screenCoordToDist",&ScreenCoordToDist); 2586 CFrogThing *ScreenCoordToX(C3DWorldManager *self,I64 *argv,I64 argc) { 2587 CD3 *p=&w->to_point[GR_WIDTH/2/4][GR_HEIGHT/2/4]; 2588 return FrogNumNew(p->x); 2589 } 2590 AddMethod("C3DWorldManager","screenCoordToX",&ScreenCoordToX); 2591 CFrogThing *ScreenCoordToY(C3DWorldManager *self,I64 *argv,I64 argc) { 2592 CD3 *p=&w->to_point[GR_WIDTH/2/4][GR_HEIGHT/2/4]; 2593 return FrogNumNew(p->y); 2594 } 2595 AddMethod("C3DWorldManager","screenCoordToY",&ScreenCoordToY); 2596 CFrogThing *ScreenCoordToZ(C3DWorldManager *self,I64 *argv,I64 argc) { 2597 CD3 *p=&w->to_point[GR_WIDTH/2/4][GR_HEIGHT/2/4]; 2598 return FrogNumNew(p->z); 2599 } 2600 AddMethod("C3DWorldManager","screenCoordToZ",&ScreenCoordToZ); 2601 C3DPoint *TileAtScreen(C3DWorldManager *man,I64 *argv,I64 argc) { 2602 C3DPoint *r=ConstructThing("C3DPoint"); 2603 r->x=man->cur_tile_x; 2604 r->y=man->cur_tile_y; 2605 r->z=man->cur_tile_z; 2606 return r; 2607 } 2608 AddMethod("C3DWorldManager","screenTile",&TileAtScreen); 2609 C3DPoint *TileSideAtScreen(C3DWorldManager *man,I64 *argv,I64 argc) { 2610 C3DPoint *r=ConstructThing("C3DPoint"); 2611 r->x=man->cur_tile_side_x; 2612 r->y=man->cur_tile_side_y; 2613 r->z=man->cur_tile_side_z; 2614 return r; 2615 } 2616 AddMethod("C3DWorldManager","screenTileSide",&TileSideAtScreen); 2617 // 2618 // World Edit section 2619 // 2620 2621 CFrogNum *WorldManagerGetShiftKey(C3DWorldManager *,I64 *argv,I64 argc) { 2622 return FrogNumNew(Bt(kbd.down_bitmap,SC_SHIFT)); 2623 } 2624 AddMethod("C3DWorldManager","getShiftKey",&WorldManagerGetShiftKey); 2625 2626 CFrogNum *WorldManagerGetTileAtXAtYAtZ(C3DWorldManager *,I64 *argv,I64 argc) { 2627 I64 x=Floor(AsF64(argv[0])); 2628 I64 y=Floor(AsF64(argv[1])); 2629 I64 z=Floor(AsF64(argv[2])); 2630 return FrogNumNew(BlockAtXYZ(x,y,z)); 2631 } 2632 AddMethod("C3DWorldManager","getTileAtX:atY:atZ:",&WorldManagerGetTileAtXAtYAtZ); 2633 CFrogNum *WorldManagerSetTileAtXAtYAtZ(C3DWorldManager *,I64 *argv,I64 argc) { 2634 I64 x=Floor(AsF64(argv[1])); 2635 I64 y=Floor(AsF64(argv[2])); 2636 I64 z=Floor(AsF64(argv[3])); 2637 if(0<=x<w->world_width) 2638 if(0<=y<w->world_height) 2639 if(I8_MIN<=z<I8_MAX) { 2640 w->world_blocks[(x+y*w->world_width)*256+z-I8_MIN]=AsF64(argv[0]); 2641 } 2642 return FROG_SMALL_NIL; 2643 } 2644 AddMethod("C3DWorldManager","setTile:atX:atY:atZ:",&WorldManagerSetTileAtXAtYAtZ); 2645 2646 2647 // 2648 // Test section 2649 // 2650 #ifdef TEST_3D 2651 DocClear; 2652 #include "UI.HC" 2653 InitWorld; 2654 I64 mp_thing_done=0; 2655 CFrogThing *UpdateParticles(C3DWorldManager *man,I64 *argv,I64 argc) { 2656 if(man->is_paused) return; 2657 I64 tx,ty; 2658 F64 fx,cx,fy,cy,dx,dy; 2659 static CFrogClass *ws_class=FrogClassNew(UniverseAddClass("CWallStain")); 2660 C3DParticle *head,*p,*n; 2661 head=&w->particles; 2662 for(p=head->next;head!=p;p=n) { 2663 n=p->next; 2664 if(!p->hit&&BlockAtXYZ(p->x/128,p->y/128,Floor(p->z))) { 2665 //Pick nearest "wall" 2666 fx=Floor(p->x/128.); 2667 cx=Ceil(p->x/128.); 2668 fy=Floor(p->y/128.); 2669 cy=Ceil(p->y/128.); 2670 dx=Min(cx-p->x/128.,p->x/128.-fx); 2671 dy=Min(cy-p->y/128.,p->y/128.-fy); 2672 if(dy<dx) { 2673 if(p->y/128-fy>.5) 2674 p->y=(fy-.1)*128; 2675 else 2676 p->y=(cy+.1)*128; 2677 } else { 2678 if(p->x/128.-fx>.5) 2679 p->x=(fx-.1)*128; 2680 else 2681 p->x=(cx+.1)*128; 2682 } 2683 if(!p->hit) 2684 goto hit; 2685 } 2686 if(C3DWorldMoveWithCollision( 2687 w, 2688 Arg(p->momx,p->momy), 2689 Sqrt(p->momx*p->momx+p->momy*p->momy), 2690 &p->x, 2691 &p->y, 2692 FALSE, 2693 p->z 2694 )) { 2695 goto hit; 2696 } 2697 if(C3DWorldMoveZWithCollision(w,p->momz,p->x,p->y,&p->z)) { 2698 goto hit; 2699 } 2700 p->momx*=20/30.; 2701 p->momy*=20/30.; 2702 p->momz-=.2; 2703 tx=p->x/GRID_SZ; 2704 ty=p->y/GRID_SZ; 2705 if(0) { 2706 hit: 2707 if(p->momz<=0.) { 2708 p->z=Floor(p->z)+.001; //Sit on floors 2709 p->hit=1; 2710 p->momz=0; 2711 stain: 2712 if(p->splat_lump_name[0]) { 2713 CallScript("newStainAtX:atY:atZ:withGraphicsLump:withSpread:",ws_class, 2714 FrogNumNew(p->x), 2715 FrogNumNew(p->y), 2716 FrogNumNew(p->z), 2717 FrogStrNew(p->splat_lump_name), 2718 FrogNumNew(32.) 2719 ); 2720 p->splat_lump_name[0]=0; 2721 } 2722 } 2723 } 2724 if(Frog_tS>1+p->born_at) { 2725 QueRem(p); 2726 Free(p); 2727 w->particle_cnt--; 2728 } 2729 } 2730 return FROG_SMALL_NIL; 2731 } 2732 AddMethod("C3DWorldManager","updateParticles",&UpdateParticles); 2733 U0 Draw3DWorld(CTask *,CDC *dc) { 2734 C3DWorldManager *man=FrogSymbol("world")->value; 2735 static CFrogClass *ws_class=FrogClassNew(UniverseAddClass("CWallStain")); 2736 man->world_handle=w; 2737 w->_wall_stains=man->wall_stains->items; 2738 w->_floor_stains=man->floor_stains->items; 2739 w->_2d_things=man->things->items; 2740 w->to_dc=dc; 2741 CDoor **doors; 2742 CDayNightStar **stars,*star; 2743 CPlayer *player=CallScript("getPlayer",man); 2744 if(player==FROG_SMALL_NIL) { 2745 return; 2746 } 2747 CFrogImg *hand_gr,*minimap; 2748 C3DLine *line; 2749 I32 *odepth_buf; 2750 I64 tx,ty,c,f; 2751 CI64Set *s; 2752 C3DParticle *p,*head,*n; 2753 CShellCasing *shellc; 2754 CHandItem *hand=FrogSymbol("hand_item")->value; 2755 w->angle2=player->angle2; 2756 w->angle=player->angle; 2757 w->x=player->x; 2758 w->y=player->y; 2759 w->cam_height=player->z+.6; 2760 DCFill(dc,man->day_night->sky_color); 2761 stars=man->day_night->stars->items->body; 2762 c=man->day_night->stars->items->cnt; 2763 while(--c>=0) { 2764 star=stars[c]; 2765 dc->color=star->color; 2766 GrFillCircle(dc,star->screen_x,star->screen_y,,star->radius/2); 2767 } 2768 DCDepthBufRst(dc); 2769 PrepareThingsForDraw(man); 2770 odepth_buf=dc->depth_buf; 2771 C3DWorldCastRays(w); 2772 mp_thing_done=0; 2773 C3DLine ***body; 2774 I64 idx; 2775 head=&w->particles; 2776 for(p=head->next;head!=p;p=n) { 2777 n=p->next; 2778 DrawParticle(w,p); 2779 } 2780 doors=man->doors->items->body; 2781 c=man->doors->items->cnt; 2782 //Rely on wall commands to choose what part of door to draw 2783 I64 cnt=man->lines->items->cnt; 2784 body=MAllocIdent(man->lines->items->body); 2785 for(idx=0;idx!=cnt;idx++) { 2786 line=body[idx]; 2787 dc->color=line->color; 2788 dc->thick=line->thick; 2789 Line3D(w,dc,&line->x0,&line->x); 2790 } 2791 Free(body); 2792 w->to_dc->depth_buf=NULL; 2793 2794 Fs->user_data=0; 2795 if(ThingHasClass(player,"CPlayer")) { 2796 if(ThingHasClass(player->shell_casings,"CFrogArray")) { 2797 s=player->shell_casings->items; 2798 body=s->body; 2799 idx=s->cnt; 2800 while(--idx>=0) { 2801 shellc=body[idx]; 2802 if(ThingHasClass(shellc,"CShellCasing")) { 2803 if(ThingHasClass(shellc->dc,"CFrogImg")) 2804 AnimDCBlot(dc,shellc->x,shellc->y,shellc->dc->dc); 2805 } 2806 } 2807 } 2808 } 2809 2810 if(ThingHasClass(hand,"CHandItem")) { 2811 if(ThingHasClass(hand_gr=hand->gr,"CFrogImg")) { 2812 c=AnimDCCnt(hand_gr->dc); 2813 f=(Frog_tS-hand->anim_start_tS)/ANIM_DELAY; 2814 if(hand->anim_no_repeat) { 2815 if(f>=c) 2816 f=c-1; 2817 else 2818 f%=c; 2819 } else 2820 f%=c; 2821 GrBlot(dc,hand->x+hand->xoff-hand_gr->dc->width/2,hand->y+hand->yoff-hand_gr->dc->height/2,hand_gr->dc+f); 2822 } 2823 } 2824 fin: 2825 /* minimap=MakeMinimap1(man,player->x,player->y,player->angle,64,player->z); 2826 GrBlot(dc,GR_WIDTH-128-16,30,minimap); 2827 DCDel(minimap);*/ 2828 dc->depth_buf=odepth_buf; 2829 w->to_dc=NULL; 2830 } 2831 2832 CFrogThing *WorldManagerEmptyWithDim(C3DWorldManager *man,I64 *argv,I64 argc) { 2833 w->world_width=AsF64(argv[0]); 2834 w->world_height=AsF64(argv[1]); 2835 Free(w->world_blocks); 2836 Free(w->world_lighting); 2837 w->world_lighting=CAlloc(256*(w->world_width*w->world_height),frog_mem_task); 2838 w->world_blocks=CAlloc(256*(w->world_width*w->world_height),frog_mem_task); 2839 CFrogDictionary *old_templates=man->thing_templates,*ot2=man->tile_templates; 2840 CallScript("initGrid",man); 2841 man->thing_templates=old_templates; 2842 man->tile_templates=ot2; 2843 w->_wall_stains=man->wall_stains->items; 2844 w->_floor_stains=man->floor_stains->items; 2845 w->_2d_things=man->things->items; 2846 return man; 2847 } 2848 AddMethod("C3DWorldManager","emptyWorldWithWidth:withHeight:",&WorldManagerEmptyWithDim); 2849 CFrogThing *WorldPhysics(C3DWorldManager *wm,I64 *argv,I64 argc) { 2850 C3DThing **body=MAllocIdent(wm->things->items->body),*thing,*player; 2851 player=CallScript("getPlayer",wm); 2852 I64 c=wm->things->items->cnt,idx; 2853 F64 t,now=AsF64(FrogTimeNow(FROG_SMALL_NIL,NULL,0)->ts); 2854 //Heres the deal. 2855 //If we are a client,we will let the server do the physics on everyting except the player 2856 if(wm->is_client) { 2857 if(ThingHasClass(player,"CPlayer")) { 2858 PhysicsOnThing(w,player,wm,0.); 2859 player->momx2=0; 2860 player->momy2=0; 2861 player->momz2=0; 2862 //interoplate things 2863 for(idx=0;idx<c;idx++) { 2864 thing=body[idx]; 2865 if(thing!=player) { 2866 //interpolate_end_tS is the time we recived,start_tS is the frame before that 2867 t=(now-thing->interpolate_end_tS)/(thing->interpolate_end_tS-thing->interpolate_start_tS); 2868 thing->x=Lerp(t,thing->server_old_x,thing->server_new_x); 2869 thing->y=Lerp(t,thing->server_old_y,thing->server_new_y); 2870 thing->z=Lerp(t,thing->server_old_z,thing->server_new_z); 2871 } 2872 } 2873 } 2874 Free(body); 2875 return FROG_SMALL_NIL; 2876 } 2877 for(idx=0;idx<c;idx++) { 2878 thing=body[idx]; 2879 //Only update when in view 2880 if(Sqr(VIEW_DIST*GRID_SZ) 2881 >Sqr(thing->y-player->y)+Sqr(thing->x-player->x)) { 2882 PhysicsOnThing(w,thing,wm,0.); 2883 if(body[idx]==player) { 2884 player->momx2=0; 2885 player->momy2=0; 2886 player->momz2=0; 2887 } 2888 } 2889 } 2890 Free(body); 2891 return FROG_SMALL_NIL; 2892 } 2893 AddMethod("C3DWorldManager","physics",&WorldPhysics); 2894 2895 2896 2897 CFrogThing *TileTemplateUpdate(CTileTemplate *tile,I64 *argv,I64 argc) { 2898 I64 idx=tile->tile_idx; 2899 CDC *dc; 2900 if(dc=w->wall_textures[idx]) 2901 AnimDCDel(dc); 2902 if(dc=w->floor_textures[idx]) 2903 AnimDCDel(dc); 2904 if(dc=w->ceil_textures[idx]) 2905 AnimDCDel(dc); 2906 if(ThingHasClass(tile->wall_texture,"CFrogImg")) { 2907 w->wall_textures[idx]=ScaleDC(tile->wall_texture->dc,128,128,frog_mem_task); 2908 } else 2909 w->wall_textures[idx]=NULL; 2910 2911 if(ThingHasClass(tile->floor_texture,"CFrogImg")) { 2912 w->floor_textures[idx]=ScaleDC(tile->floor_texture->dc,128,128,frog_mem_task); 2913 } else 2914 w->floor_textures[idx]=NULL; 2915 2916 if(ThingHasClass(tile->ceil_texture,"CFrogImg")) { 2917 w->ceil_textures[idx]=ScaleDC(tile->ceil_texture->dc,128,128,frog_mem_task); 2918 } else 2919 w->ceil_textures[idx]=NULL; 2920 return FROG_SMALL_NIL; 2921 } 2922 AddMethod("CTileTemplate","updateTextures",&TileTemplateUpdate); 2923 2924 CFrogNum *WallStainPlaceAtXYZ(CWallStain *ws,I64 *argv,I64 argc) { 2925 F64 x=AsF64(argv[0])/128; 2926 F64 y=AsF64(argv[1])/128; 2927 F64 z=AsF64(argv[2]); 2928 F64 fz=Floor(z); 2929 F64 cz=Ceil(z); 2930 F64 fx=Floor(x); 2931 F64 cx=Ceil(x); 2932 F64 fy=Floor(y); 2933 F64 cy=Ceil(y); 2934 2935 ws->tile_x=fx; 2936 ws->tile_y=fy; 2937 ws->tile_z=fz; 2938 2939 //Realy close to z==fz,so test for empty side 2940 if(Abs(z-fz)<1./256) { 2941 if(0==BlockAtXYZ(ws->tile_x,ws->tile_y,ws->tile_z)) 2942 goto fzc; 2943 } 2944 if(Abs(z-cz)<1./256) { 2945 if(0==BlockAtXYZ(ws->tile_x,ws->tile_y,ws->tile_z-1)) { 2946 ws->tile_z--; 2947 goto czc; 2948 } 2949 } 2950 if(Abs(x-fx)<1./256) { 2951 if(0==BlockAtXYZ(ws->tile_x,ws->tile_y,ws->tile_z)) 2952 goto fxc; 2953 } 2954 if(Abs(x-cx)<1./256) { 2955 if(0==BlockAtXYZ(ws->tile_x-1,ws->tile_y,ws->tile_z)) { 2956 ws->tile_x--; 2957 goto cxc; 2958 } 2959 } 2960 if(Abs(y-fy)<1./256) { 2961 if(0==BlockAtXYZ(ws->tile_x,ws->tile_y,ws->tile_z)) 2962 goto fyc; 2963 } 2964 if(Abs(y-cy)<1./256) { 2965 if(0==BlockAtXYZ(ws->tile_x,ws->tile_y-1,ws->tile_z)) { 2966 ws->tile_y--; 2967 goto cyc; 2968 } 2969 } 2970 2971 if(z<fz+.1) { 2972 fzc: 2973 ws->sidez=1; 2974 ws->center_x=ToI64(x*128-ws->tile_x*128); 2975 ws->center_y=ToI64(y*128-ws->tile_y*128); 2976 ws->tile_z--; 2977 final: 2978 if(BlockAtXYZ(ws->tile_x,ws->tile_y,ws->tile_z)) { 2979 return FrogNumNew(0==BlockAtXYZ(ws->tile_x+ws->sidex,ws->tile_y+ws->sidey,ws->tile_z+ws->sidez)); 2980 } 2981 return FrogNumNew(0); 2982 } 2983 2984 if(z>cz-.1) { 2985 czc: 2986 ws->sidez=-1; 2987 ws->center_x=ToI64(x*128-ws->tile_x*128); 2988 ws->center_y=ToI64(y*128-ws->tile_y*128); 2989 ws->tile_z++; 2990 goto final; 2991 } 2992 if(x<fx+.1) { 2993 fxc: 2994 ws->sidex=1; 2995 ws->center_x=y*128-ws->tile_y*128; 2996 ws->center_y=z*128-ws->tile_z*128; 2997 ws->tile_x--; 2998 goto final; 2999 } 3000 if(x>cx-.1) { 3001 cxc: 3002 ws->sidex=-1; 3003 ws->center_x=y*128-ws->tile_y*128; 3004 ws->center_y=z*128-ws->tile_z*128; 3005 ws->tile_x++; 3006 goto final; 3007 } 3008 if(y<fy+.1) { 3009 fyc: 3010 ws->sidey=1; 3011 ws->center_x=x*128-ws->tile_x*128; 3012 ws->center_y=z*128-ws->tile_z*128; 3013 ws->tile_y--; 3014 goto final; 3015 } 3016 if(y>cy-.1) { 3017 cyc: 3018 ws->sidey=-1; 3019 ws->center_x=x*128-ws->tile_x*128; 3020 ws->center_y=z*128-ws->tile_z*128; 3021 ws->tile_y++; 3022 goto final; 3023 } 3024 return FrogNumNew(0); 3025 } 3026 AddMethod("CWallStain","placeAtX:atY:atZ:",&WallStainPlaceAtXYZ); 3027 CWallStain *WallStainTryMerge(CWallStain *have) { 3028 C3DWorldManager *man=FrogSymbol("world")->value; 3029 I64 cnt; 3030 CWallStain **body,*got; 3031 CFrogArray *arr=CallScript("at:", 3032 CallScript("at:",man->stains_grid, 3033 FrogNumNew(have->tile_x/4)), 3034 FrogNumNew(have->tile_y/4) 3035 ); 3036 arr=man->wall_stains; 3037 if(ThingHasClass(arr,"CFrogArray")) { 3038 cnt=arr->items->cnt; 3039 body=arr->items->body; 3040 while(--cnt>=0) { 3041 got=body[cnt]; 3042 if(got->tile_x==have->tile_x&& 3043 got->tile_y==have->tile_y&& 3044 got->tile_z==have->tile_z&& 3045 got->sidex==have->sidex&& 3046 got->sidey==have->sidey&& 3047 got->sidez==have->sidez 3048 ) { 3049 return got; 3050 } 3051 } 3052 } 3053 got=ConstructThing("CWallStain"); 3054 got->tile_x=have->tile_x; 3055 got->tile_y=have->tile_y; 3056 got->tile_z=have->tile_z; 3057 got->sidex=have->sidex; 3058 got->sidey=have->sidey; 3059 got->sidez=have->sidez; 3060 CallScript("addWallStain:",man,got); 3061 return got; 3062 } 3063 CFrogNum *WallStainPutGraphics(CWallStain *ws,I64 *argv,I64 argc) { 3064 C3DWorldManager *man=FrogSymbol("world")->value; 3065 CFrogStr *lump_name=argv[0]; 3066 CFrogImg *img=CallScript("get:", 3067 FrogClassNew(UniverseAddClass("CFrogImg")), 3068 lump_name 3069 ); 3070 CWallStain *new; 3071 F64 x=AsF64(argv[1]); 3072 F64 y=AsF64(argv[2]); 3073 I64 xx,yy,zz; 3074 I64 ox=ws->tile_x,oy=ws->tile_y,oz=ws->tile_z; 3075 if(!ws->sidez) { 3076 for(zz=-1;zz<=1;zz++) { 3077 for(xx=-1;xx<=1;xx+=2) { 3078 if(BlockAtXYZ(ox+xx,oy,oz+zz)) { 3079 ws->tile_x=ox+xx; 3080 ws->tile_y=oy; 3081 ws->tile_z=oz+zz; 3082 new=WallStainTryMerge(ws); 3083 if(AsF64(CallScript("addGraphics:atX:atY:",new,img, 3084 FrogNumNew(x-xx*128), 3085 FrogNumNew(y-zz*128)))) { 3086 } 3087 } 3088 } 3089 for(yy=-1;yy<=1;yy+=2) { 3090 if(BlockAtXYZ(ox,oy+yy,oz+zz)) { 3091 ws->tile_x=ox; 3092 ws->tile_y=oy+yy; 3093 ws->tile_z=oz+zz; 3094 new=WallStainTryMerge(ws); 3095 if(AsF64(CallScript("addGraphics:atX:atY:",new,img, 3096 FrogNumNew(x-yy*128), 3097 FrogNumNew(y-zz*128)))) { 3098 } 3099 } 3100 } 3101 } 3102 } 3103 if(ws->sidez) 3104 for(yy=-1;yy<=1;yy++) { 3105 for(xx=-1;xx<=1;xx++) { 3106 if(xx||yy) { 3107 ws->tile_x=ox+xx; 3108 ws->tile_y=oy+yy; 3109 ws->tile_z=oz; 3110 new=WallStainTryMerge(ws); 3111 if(AsF64(CallScript("addGraphics:atX:atY:",new,img, 3112 FrogNumNew(x-xx*128), 3113 FrogNumNew(y-yy*128)))) { 3114 } 3115 } 3116 } 3117 } 3118 ws->tile_x=ox; 3119 ws->tile_y=oy; 3120 ws->tile_z=oz; 3121 new=WallStainTryMerge(ws); 3122 if(AsF64(CallScript("addGraphics:atX:atY:",new,img, 3123 FrogNumNew(x), 3124 FrogNumNew(y)))) { 3125 } 3126 } 3127 AddMethod("CWallStain","putGraphics:atX:atY:",&WallStainPutGraphics); 3128 // 3129 // 3130 // 3131 #if __CMD_LINE__ 3132 CallScript("newLandscapeWithWidth:withHeight:",FrogSymbol("world")->value,FrogNumNew(10),FrogNumNew(10)); 3133 C3DWorldShell *shell=ConstructThing("C3DWorldShell"); 3134 CallScript("init",shell); 3135 UIShellRun(shell,NULL,0); 3136 #endif 3137 #endif 3138 #endif