ãšã³ãžã³ãæžãããã«ãªã£ããã£ãã
ç©èªã¯ããªãåã«å§ãŸããVista 64ã§çŽ æŽãããããžãã¯ããºã«ãããã·ã£ãŒãããã¬ã€ãããã£ããšããäºå®ããå§ãŸããŸãããããããå ã®ã²ãŒã ã¯16ãããã§ãããéå§ãå®å šã«æåŠããŸããã Cã§ã¯ããŒã³ãæžãããšã»ã©è¯ãããšã¯ãããŸããã§ããïŒæåã¯ããè¯ãçµæã«ã€ãªããæè¯ã®ãœãªã¥ãŒã·ã§ã³ã§ã¯ãªãããšããããŸãïŒã ãã°ããããŠã SDL v1.2 + OpenGLãã©ãããã©ãŒã ã§ã²ãŒã ãå®è£ ããŸããã
ããã転éã®å©äŸ¿æ§ã®ããã«ãã¬ãã«ãšãã£ã¿ãŒãè¿œå ãã64æã®ã«ãŒããã¹ãŠãæåã§è€è£œããŸããã ãã°ããããŠããããã·ã£ãŒããžã®é¢å¿ãèããç§ã¯ãã§ã«3dfxã°ã©ãã£ãã¯ã¹ã§ãã¥ãŒã ã¬ã€ã㌠1ãé転ããããšæã£ãŠããŸããã ãããŠãå€ãã®äººããã§ã«æšæž¬ããŠããããã«ããããè¡ãããã®æ¢åã®è§£æ±ºçã¯ïŒãããã䞻芳çã«ããïŒç§ãæ¬åœã«åã°ãããããŒããæ¢ãå§ããŸããã æåãªOpen raiderãããžã§ã¯ãã«å ããŠãäœãèŠã€ãããŸããã§ããã ç§ã¯mingwã³ã³ãã€ã©ã䜿çšããŠWindowsã§ãã«ãããããšã§èŠããã ããšãä»ã§ãèŠããŠããŸãïŒéçºç°å¢ã ã³ãŒã::ãããã¯ãŸãã¯netbeansã®ãããããèŠããŠããŸããïŒã ãã«ãçµæã¯ãŸã£ããç§ãåã°ããŸããã§ããïŒçŽ1åéã¬ãã«ãããŒãããæåŸã«é»ãç»é¢ã衚瀺ããŸããã ä»ã®äººã®ã³ãŒããéžæãããã®æ§é ãšé¢æ°ã®æå³ãç解ããèœåã¯ãããŸããã§ããã ãããè¯ããããŸãšããè©Šã¿ã¯åæ¢ããŸããã ãã ãããªãŒãã³ãšã³ãžã³ã®å°ãªããšã1ã€ãæåã§ã¢ã»ã³ãã«ãããšããã¢ã€ãã¢ãåŸãŸãããDieGNU Autotoolsã® auto-configã§ã¯ãªããéçºç°å¢ã®èªå·±ã¢ã»ã³ãã«ããããã¶ã€ããŒããã§ãã
ãããã£ãŠãã¢ãã¿ãŒã®åŸãã«ããªãã®æéã眮ããåŸãäžå®éã®ããããªã©ã眮ããŠãé³ã®ãªãQuake Tenebraeãçµã¿ç«ãŠãŸãã ã ãããã圌ã¯åããïŒ ç§ã¯ä»ã®äººã®ã³ãŒããããããç解ãå§ããæçµçã«ã³ã³ãã€ã©ã®çµç¹ã®å°ãªããšãäœããç解ãå§ããŸãã-ãããªãã§ã¯äžå¯èœã§ãã ãã®åŸãããã€ãã®ãã€ããŒãªæ¹åãè¡ãããããã€ãã®ãã°ãä¿®æ£ããããµãŠã³ããéå§ãããŸãããããããžã§ã¯ãã¯ã€ã³ã¿ãŒãããã«ã¢ããããŒããããŸããã§ããïŒããã§ããç¹ã«ããŒã¯ãã¬ãŒã¹ãšã³ãžã³ã®ååšãèæ ®ãããšãé埳çã«å»æ¢ãããŸããïŒã ãã ãã Quake Tenebraeãšã³ãžã³ã³ãŒããããã²ãŒã å šäœã®äœæ¥ãåã ã®ã³ã³ããŒãã³ããããã³ã¡ã¢ãªãããŒãžã£ãŒãã©ã®ããã«ç·šæãããŠããããåŠã³ãŸããïŒéåžžã«åçŽã§ã¯ãããŸããã reallocé¢æ°ãè¿œå ããŸããããã¯ã©ãã·ã¥ããããšãªãæ©èœããŸããïŒã
ãšã³ãžã³ãæžã
å°ãæ £ãããšããšã³ãžã³ããŒãããæžãå§ããããšã«ããŸããã 楜ãã¿ãšèªå·±åçºã®ããã ãã«ã ãšã³ãžã³ã®äœæã®åºç€ã¯æ¬¡ã®ãšããã§ããGCC-TDMv4.X.X + msysã³ã³ãã€ã©ãŒããã³Netbeanséçºç°å¢ã ã©ã€ãã©ãªïŒ SDL v1.2 + OpenGL å®è£ ãããæåã®æ©èœã¯ãã¹ã¯ãªãŒã³ã·ã§ãããæ®ãã*ãbmpãã¡ã€ã«ã«ä¿åããããšã§ããã®åœ¢åŒã§åäœããããã«èªå·±èšè¿°ã©ã€ãã©ãªã䜿çšããŠããŸããã ã³ãã³ã
char *parse_token(char *data, char *token) { int c; int len; len = 0; token[0] = 0; if(!data) { return NULL; } // skip whitespace skipwhite: while((c = *data) <= ' ') { if(c == 0) return NULL; // end of file; data++; } // skip // comments if (c=='/' && data[1] == '/') { while (*data && *data != '\n') data++; goto skipwhite; } // handle quoted strings specially if (c == '\"') { data++; while (1) { c = *data++; if (c=='\"' || !c) { token[len] = 0; return data; } token[len] = c; len++; } } // parse single characters if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') { token[len] = c; len++; token[len] = 0; return data+1; } // parse a regular word do { token[len] = c; data++; len++; c = *data; if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') { break; } } while (c>32); token[len] = 0; return data; }
å ã«é²ãïŒã¹ã¯ãªããã®ãµããŒããå¿ èŠã«ãªã£ããšããDOOM 3ãšã³ãžã³ã®äŸã䜿çšããŠIDãœãããŠã§ã¢ã®ããã«ãšã³ãžã³ãéçºããã¢ãããŒãã䜿çšããããšã«ããŸãããããã¯Habré=ã§ããã§éåžžã«ãã説æãããŸããã翻蚳ãšããã«èå³æ·±ãã³ã¡ã³ããæžãã人ïŒã ãã®èšäºã«æéãåããã²ãŒã å ã®ã¹ã¯ãªããäœæã®ããŒãºã ãã§ãªããæ§æãã¡ã€ã«ãšã³ã³ãœãŒã«ã³ãã³ãã®è§£æã«ãLUAããšã³ãžã³ã«å®è£ ããããšã«ããŸããïŒã€ãŸããã©ãã§ãçµ±äžãããã·ã¹ãã ã䜿çšãããŠããŸãïŒã ãã®ã¢ãããŒãã¯å®å šã«ææãäžããŸããã
3Dã«ç§»ããŸããã
ç 究æã§ã¯ãç·åœ¢ä»£æ°ãè¡åå€ââæããã¯ãã«ãæ°å€æ³ã奜ãã ã£ãã®ã¯å¹žéã§ããã ãããã®åºæ¬ããªããã°ããšã³ãžã³ã®ããã°ã©ãã³ã°ããŒãããå§ããã®ã¯éåžžã«ç¡è¬ã§ãïŒãã ãããããã®ã»ã¯ã·ã§ã³ãäŸã§ç 究ããããã«ç¹å®ã®çè«çç¥èããŒã¹ããªããã°ãããã¯ã»ãšãã©çŸå®çã§ã¯ãããŸããïŒã A.ãã¬ã¹ã³ãã®èæžãOPENGLã«åºã¥ãã3次å ã³ã³ãã¥ãŒã¿ãŒã²ãŒã ã®ã°ã©ãã£ãã¯ã¹ãã¯ãã°ã©ãã£ãã¯ã¹ããã¹ã¿ãŒããã®ã«å€§ãã«åœ¹ç«ã¡ãŸããã æ°åŠçè£ çœ®ãã¬ã³ãã©ãŒã®ã¿ã€ãããšã³ãžã³ã®æ§é ã«æ £ããããã«ãç§ã¯ãããäœåºŠãèªã¿çŽããŸããã ã·ãŒã³ãæ§ç¯ããåçãšçš®ãããªãã¯ã¹ãšæ圱ãããªãã¯ã¹ã®ç®çã®æŠå¿µããªããã°ãé²æ©ã¯äžå¯èœã§ãã ã€ã³ã¿ãŒãããäžã®ããã€ãã®è³æãšåãªãæç®ãç 究ããåŸãç§ã¯ããŒã¿ã«ã¬ã³ãã©ãŒãå®è¡ããããšã«ããŸããã ãšã³ãžã³ã«æåã«å®è£ ãããã®ã¯ãèªç±ã«é£è¡ããã«ã¡ã©ãšãäºãã«ããèŠããªãããã€ãã®ããŒã¿ã«ã§ããã
ããŒãã³ãŒãã®åŸã3ã€ã®éšå±ã®ã¯ã€ã€ãŒãã¬ãŒã ã·ãŒã³ãè¿œå ãããŸããïŒããã«2ã€ãšå»äžïŒã ãããããã®ãããªåå§çãªäžçãé£ã³åãããšã¯æ¬åœã«èå³æ·±ãã®ã§ãããã...ãããŠã Open Raiderã®ãªãœãŒã¹ã¬ã€ã¶ãŒã䜿çšããŠã¬ãã«ãã¬ã³ããªã³ã°ããããšã«ããŸããã çµæã¯ç§ãåã°ããããã§å°ãªããšãæåã®éšåã§ã ãã¥ãŒã ã¬ã€ããŒããã¬ã€ããããã®ããŒããäœæããèšç»ãå®è£ ããããšãæçµçã«æ±ºå®ãããŸããã ãªããžã§ã¯ãã空éã«é 眮ããããã«ãOpenGLãããªãã¯ã¹ã䜿çšããŸãããããã«ããããªããžã§ã¯ãã®ããŒã«ã«åº§æšç³»ã®åºæ¬ãã¯ãã«ã«ã¢ã¯ã»ã¹ãã1ã€ã®ã³ãã³ãglMultMatrixf ïŒå€æïŒã§ãªããžã§ã¯ãã®äœçœ®ãèšå®ãã1ã€ã®setFromOpenGLMatrix ïŒå€æïŒã³ãã³ãã§ãªããžã§ã¯ãã®æ¹åãèšå®ããŸãå°ãåŸã§ã 以äžã¯ãäžèšã®ãªã³ã¯ã®OpenGLãããªãã¯ã¹æ§é ã®ç»åã§ãã
ãšã³ãžã³ã®å€æŽå±¥æŽãšããã¯ã¢ããã®å¯èœæ§ãç¶æããããã«ããŸãèªå·±éçºã®ããã ãã«ã æ°ŽéããŒãžã§ã³ç®¡çã·ã¹ãã ã䜿çšããããšã決å®ãããŸããã ãã®ã¢ããªã±ãŒã·ã§ã³ã«ãããã³ãŒãã®èšè¿°ã®é²è¡ç¶æ³ã远跡ã§ããã ãã§ãªããçµæãsourceforge.comã«ã¢ããããŒãããããšãå¯èœã«ãªããŸããã å®éã®ãããããã®ããŒã¿ã«ã«é¢ããæ å ±ããšã³ãžã³ã«èªã¿èŸŒãŸãå§ãããšããããŒã¿ã«ã·ã¹ãã ã®å®è£ ã«ãããèšå€§ãªæ°ã®æ¬ é¥ãããã«è¡šé¢åããããšã«æ³šæããå¿ èŠããããŸãã ãªããžã§ã¯ãã®æ¶å€±ãã¯ã©ãã·ã¥ã®åŠçã«ã¯å€ãã®æéãããããŸããããä»ã§ãããŒã¿ã«ã¢ãžã¥ãŒã«ã«ã¯é倧ãªä¿®æ£ãå¿ èŠã ãšæããŸãã ãšã³ãžã³ã¬ã³ãã©ãŒã¯ãã«ã¡ã©ã®äœçœ®ãšåãã«å¿ããŠãéšå±ã®ããŒã¿ã«ãééãå§ãã衚瀺ãããŠããéšå±ã®ã¿ããªã¹ãã«è¿œå ããŸãã 次ã«ãã¬ã³ãã©ãŒã¯ããªã¹ãããã«ãŒã ãšãã®ã³ã³ãã³ããæç»ããŸãã 倧èŠæš¡ãªãªãŒãã³ã¹ããŒã¹ã®å Žåããã®ã¢ãããŒããæãæåããŠããããã§ã¯ãªãããšã¯æããã§ããããããžã§ã¯ãã®ç®çã«ã¯ååã§ãã ååž°çã«ãŒã ãã©ããŒãµã«é¢æ°ã®äŸã次ã«ç€ºããŸãã
** * The reccursion algorithm: go through the rooms with portal - frustum occlusion test * @portal - we entered to the room through that portal * @frus - frustum that intersects the portal * @return number of added rooms */ int Render_ProcessRoom(struct portal_s *portal, struct frustum_s *frus) { int ret = 0, i; room_p room = portal->dest_room; // room_p src_room = portal->current_room; // portal_p p; // - frustum_p gen_frus; // if((src_room == NULL) || !src_room->active || (room == NULL) || !room->active) { return 0; } p = room->portals; for(i=0; i<room->portal_count; i++,p++) // { if((p->dest_room->active) && (p->dest_room != src_room)) // { gen_frus = Portal_FrustumIntersect(p, frus, &renderer); // - . if(NULL != gen_frus) // { ret++; Render_AddRoom(p->dest_room); Render_ProcessRoom(p, gen_frus); } } } return ret; }
éªšæ Œã¢ãã¡ãŒã·ã§ã³ã¢ãã«
ãããŠããããžã§ã¯ãã§æã骚ã®æããäœæ¥ã®1ã€ãå§ãŸããŸããã éçãªããžã§ã¯ãã䜿çšããéçã«ãŒã ã®ã¬ã³ããªã³ã°ã¯æ¯èŒçç°¡åã§ããããã¢ãã¡ãŒã·ã§ã³åãããéªšæ Œã¢ãã«ã«é¢ããŠã¯...æåã«æ°ä»ããã®ã¯ã Open RaiderãªãœãŒã¹ããŒããŒãéªšæ Œã¢ãã«ã«é¢ãããã¹ãŠã®å¿ èŠãªæ å ±ãããŒãããªãããšã§ãã ã¢ãã¡ãŒã·ã§ã³ã®ãã¬ãŒã æ°ãæ£ãã決å®ãããŠããªãããã1ã€ã®ã¢ãã¡ãŒã·ã§ã³ã«è€æ°ã®ãã¬ãŒã ãåæã«å«ãŸããŠããŸãã
ãããã®åé¡ã解決ããããšããŠããéã«ãç§ã¯ãã¥ãŒã ã¬ã€ããŒã¬ãã«ã®ãã©ãŒããããšãåæã«ç¬èªã®ãªãœãŒã¹ããŒããŒãåããvtãããžã§ã¯ãã«é¢ããããŸããŸãªããã¥ã¡ã³ããèŠã€ããŸããã ãã®ãããžã§ã¯ãã«ã¯ãã¢ãã«ã¢ãã¡ãŒã·ã§ã³ã®ããŒããã¬ãŒã ã¯ãããŸããã§ããããããæ§é åãããã³ãŒããå«ãŸããŠããŠãèªã¿ããããé ã«æµ®ãã¶ã®ã«äŸ¿å©ã§ãã ããã§ããããžã§ã¯ãã®ããŒããŒãvtã«çœ®ãæããŸããã ããšãã°ã ãªãŒãã³ã¬ã€ããŒã§ã¯ã ãã¥ãŒã ã¬ã€ããŒã® 5ã€ã®éšåãã¹ãŠã«1ã€ã®é·ãé¢æ°ãããŒããããå€æ°ã®ifãšã¹ã€ãããã²ãŒã ã®ããŒãžã§ã³çªå·ã«ãã£ãŠåãæ¿ãããŸããããã«ãããã³ãŒãã®èªã¿åããšãšã©ãŒã®æ€åºãå€§å¹ ã«è€éã«ãªããŸãã vtã«ã¯5ã€ã®ã¢ãžã¥ãŒã«ãããããããããã¬ãã«ã®ç¬èªã®ããŒãžã§ã³ãæ åœããŠãããããã³ãŒãã¯èªã¿ããããå€æŽã¯é£ãããããŸããã§ããã
ã¢ãã¡ãŒã·ã§ã³ã®äž»ãªåé¡ã¯ãéªšæ Œã¢ãã«ã®éªšã®å転è§åºŠã®æœåºã§ããã å®éã«ã¯ãã¹ããŒã¹ãç¯çŽããããã«ãã³ãŒããŒã¯2ã4ãã€ãåäœã§ãã€ãã³ãŒãã«æ ŒçŽãããŠããŸããã æåã®2ãã€ãã«ã¯ãããã§ã©ã®è»žã®åšãã«1ã¿ãŒã³ããããããŸãã¯3ã€ã®ã³ãŒããŒèªäœããããã©ããã«é¢ãããã©ã°ãå«ãŸããŠããŸãã 3ã¿ãŒã³ã®å Žåããã©ã°ãšã³ãŒããŒã¯4ãã€ãã§æ ŒçŽããã1ã¿ãŒã³ã®å Žåã¯2ãã€ãã®ã¿ã䜿çšãããŸãã ããã«ããã¹ãŠã®ã¢ãã«ãã¢ãã¡ãŒã·ã§ã³ãããã³ãã¬ãŒã ã®è§åºŠã¯1ã€ã®é åã«ä¿åããããªãã»ãããèšç®ããå¿ èŠããããŸãã ããã«ãã¢ãã«ã®åã ã®ãã¬ãŒã ã®ããããŒã¯ãã®ãã€ãã³ãŒãã«ä¿åããããŸãŸã§ããããªãã»ãããšã®æ··ä¹±ãéèŠã§ããããã¬ãŒã æ°ã誀ã£ãŠèªã¿èŸŒãŸããããšãè¿œå ããŸããïŒåŸã§ããã¬ãŒã æ°ã30 fpsã®ãè£éãã¢ãã¡ãŒã·ã§ã³ã«äžããããããšãããããŸããããå®éã«ã¯ããã¬ãŒã ã¯ã1ã1 / 2ã1 / 3ã1 / 4ã®ãã¡ã¯ã¿ãŒãæã€fpsã®ãã¹ãããã·ã§ããã圢åŒã§ä¿åã§ããŸãã ã¢ãã¡ãŒã·ã§ã³ãã¬ãŒã ããŒããŒã®å®äºåŸãéªšæ Œã¢ãã«ã¯è£è¿ãã«ãªãããæªãã ããªãŽã³ããæ··ä¹±ã«å€ãããŸããïŒ æ¬¡ã«ãã©ã©ãã埩掻ããããå¿ èŠããããŸãã 以äžã¯ãéªšæ Œã¢ãã«ãçæããé¢æ°ã®ã³ãŒãã§ããããããã°çšã®ã³ãŒãã®ã¹ãã«ãšã³ã¡ã³ãã¢ãŠããããã»ã¯ã·ã§ã³ãä¿åãããŸãã
void GenSkeletalModel(struct world_s *world, size_t model_num, struct skeletal_model_s *model, class VT_Level *tr) { int i, j, k, l, l_start; tr_moveable_t *tr_moveable; tr_animation_t *tr_animation; uint32_t frame_offset, frame_step; uint16_t *frame, temp1, temp2; ///@FIXME: "frame" set, but not used float ang; btScalar rot[3]; bone_tag_p bone_tag; bone_frame_p bone_frame; mesh_tree_tag_p tree_tag; animation_frame_p anim; tr_moveable = &tr->moveables[model_num]; // original tr structure model->collision_map = (uint16_t*)malloc(model->mesh_count * sizeof(uint16_t)); model->collision_map_size = model->mesh_count; for(i=0;i<model->mesh_count;i++) { model->collision_map[i] = i; } model->mesh_tree = (mesh_tree_tag_p)malloc(model->mesh_count * sizeof(mesh_tree_tag_t)); tree_tag = model->mesh_tree; tree_tag->mesh2 = NULL; for(k=0;k<model->mesh_count;k++,tree_tag++) { tree_tag->mesh = model->mesh_offset + k; tree_tag->mesh2 = NULL; tree_tag->flag = 0x00; vec3_set_zero(tree_tag->offset); if(k == 0) { tree_tag->flag = 0x02; vec3_set_zero(tree_tag->offset); } else { uint32_t *tr_mesh_tree = tr->mesh_tree_data + tr_moveable->mesh_tree_index + (k-1)*4; tree_tag->flag = tr_mesh_tree[0]; tree_tag->offset[0] = (float)((int32_t)tr_mesh_tree[1]); tree_tag->offset[1] = (float)((int32_t)tr_mesh_tree[3]); tree_tag->offset[2] =-(float)((int32_t)tr_mesh_tree[2]); } } /* * ================= now, animation loading ======================== */ if(tr_moveable->animation_index < 0 || tr_moveable->animation_index >= tr->animations_count) { /* * model has no start offset and any animation */ model->animation_count = 1; model->animations = (animation_frame_p)malloc(sizeof(animation_frame_t)); model->animations->frames_count = 1; model->animations->frames = (bone_frame_p)malloc(model->animations->frames_count * sizeof(bone_frame_t)); bone_frame = model->animations->frames; model->animations->id = 0; model->animations->next_anim = NULL; model->animations->next_frame = 0; model->animations->state_change = NULL; model->animations->state_change_count = 0; model->animations->original_frame_rate = 1; bone_frame->bone_tag_count = model->mesh_count; bone_frame->bone_tags = (bone_tag_p)malloc(bone_frame->bone_tag_count * sizeof(bone_tag_t)); vec3_set_zero(bone_frame->pos); vec3_set_zero(bone_frame->move); bone_frame->v_Horizontal = 0.0; bone_frame->v_Vertical = 0.0; bone_frame->command = 0x00; for(k=0;k<bone_frame->bone_tag_count;k++) { tree_tag = model->mesh_tree + k; bone_tag = bone_frame->bone_tags + k; rot[0] = 0.0; rot[1] = 0.0; rot[2] = 0.0; vec4_SetTRRotations(bone_tag->qrotate, rot); vec3_copy(bone_tag->offset, tree_tag->offset); } return; } //Sys_DebugLog(LOG_FILENAME, "model = %d, anims = %d", tr_moveable->object_id, GetNumAnimationsForMoveable(tr, model_num)); model->animation_count = GetNumAnimationsForMoveable(tr, model_num); if(model->animation_count <= 0) { /* * the animation count must be >= 1 */ model->animation_count = 1; } /* * Ok, let us calculate animations; * there is no difficult: * - first 9 words are bounding box and frame offset coordinates. * - 10's word is a rotations count, must be equal to number of meshes in model. * BUT! only in TR1. In TR2 - TR5 after first 9 words begins next section. * - in the next follows rotation's data. one word - one rotation, if rotation is one-axis (one angle). * two words in 3-axis rotations (3 angles). angles are calculated with bit mask. */ model->animations = (animation_frame_p)malloc(model->animation_count * sizeof(animation_frame_t)); anim = model->animations; for(i=0;i<model->animation_count;i++,anim++) { tr_animation = &tr->animations[tr_moveable->animation_index+i]; frame_offset = tr_animation->frame_offset / 2; l_start = 0x09; if(tr->game_version == TR_I || tr->game_version == TR_I_DEMO || tr->game_version == TR_I_UB) { l_start = 0x0A; } frame_step = tr_animation->frame_size; //Sys_DebugLog(LOG_FILENAME, "frame_step = %d", frame_step); anim->id = i; anim->next_anim = NULL; anim->next_frame = 0; anim->original_frame_rate = tr_animation->frame_rate; anim->accel_hi = tr_animation->accel_hi; anim->accel_hi2 = tr_animation->accel_hi2; anim->accel_lo = tr_animation->accel_lo; anim->accel_lo2 = tr_animation->accel_lo2; anim->speed = tr_animation->speed; anim->speed2 = tr_animation->speed2; anim->anim_command = tr_animation->anim_command; anim->num_anim_commands = tr_animation->num_anim_commands; anim->state_id = tr_animation->state_id; anim->unknown = tr_animation->unknown; anim->unknown2 = tr_animation->unknown2; anim->frames_count = GetNumFramesForAnimation(tr, tr_moveable->animation_index+i); //Sys_DebugLog(LOG_FILENAME, "Anim[%d], %d", tr_moveable->animation_index, GetNumFramesForAnimation(tr, tr_moveable->animation_index)); // Parse AnimCommands // Max. amount of AnimCommands is 255, larger numbers are considered as 0. // See http://evpopov.com/dl/TR4format.html#Animations for details. if( (anim->num_anim_commands > 0) && (anim->num_anim_commands <= 255) ) { // Calculate current animation anim command block offset. int16_t *pointer = world->anim_commands + anim->anim_command; for(uint32_t count = 0; count < anim->num_anim_commands; count++, pointer++) { switch(*pointer) { case TR_ANIMCOMMAND_PLAYEFFECT: case TR_ANIMCOMMAND_PLAYSOUND: // Recalculate absolute frame number to relative. ///@FIXED: was unpredictable behavior. *(pointer + 1) -= tr_animation->frame_start; pointer += 2; break; case TR_ANIMCOMMAND_SETPOSITION: // Parse through 3 operands. pointer += 3; break; case TR_ANIMCOMMAND_JUMPDISTANCE: // Parse through 2 operands. pointer += 2; break; default: // All other commands have no operands. break; } } } if(anim->frames_count <= 0) { /* * number of animations must be >= 1, because frame contains base model offset */ anim->frames_count = 1; } anim->frames = (bone_frame_p)malloc(anim->frames_count * sizeof(bone_frame_t)); /* * let us begin to load animations */ bone_frame = anim->frames; frame = tr->frame_data + frame_offset; for(j=0;j<anim->frames_count;j++,bone_frame++,frame_offset+=frame_step) { frame = tr->frame_data + frame_offset; bone_frame->bone_tag_count = model->mesh_count; bone_frame->bone_tags = (bone_tag_p)malloc(model->mesh_count * sizeof(bone_tag_t)); vec3_set_zero(bone_frame->pos); vec3_set_zero(bone_frame->move); bone_frame->v_Horizontal = 0.0; bone_frame->v_Vertical = 0.0; bone_frame->command = 0x00; GetBFrameBB_Pos(tr, frame_offset, bone_frame); if(frame_offset < 0 || frame_offset >= tr->frame_data_size) { //Con_Printf("Bad frame offset"); for(k=0;k<bone_frame->bone_tag_count;k++) { tree_tag = model->mesh_tree + k; bone_tag = bone_frame->bone_tags + k; rot[0] = 0.0; rot[1] = 0.0; rot[2] = 0.0; vec4_SetTRRotations(bone_tag->qrotate, rot); vec3_copy(bone_tag->offset, tree_tag->offset); } } else { l = l_start; for(k=0;k<bone_frame->bone_tag_count;k++) { tree_tag = model->mesh_tree + k; bone_tag = bone_frame->bone_tags + k; rot[0] = 0.0; rot[1] = 0.0; rot[2] = 0.0; vec4_SetTRRotations(bone_tag->qrotate, rot); vec3_copy(bone_tag->offset, tree_tag->offset); switch(tr->game_version) { case TR_I: /* TR_I */ case TR_I_UB: case TR_I_DEMO: temp2 = tr->frame_data[frame_offset + l]; l ++; temp1 = tr->frame_data[frame_offset + l]; l ++; rot[0] = (float)((temp1 & 0x3ff0) >> 4); rot[2] =-(float)(((temp1 & 0x000f) << 6) | ((temp2 & 0xfc00) >> 10)); rot[1] = (float)(temp2 & 0x03ff); rot[0] *= 360.0 / 1024.0; rot[1] *= 360.0 / 1024.0; rot[2] *= 360.0 / 1024.0; vec4_SetTRRotations(bone_tag->qrotate, rot); break; default: /* TR_II + */ temp1 = tr->frame_data[frame_offset + l]; l ++; if(tr->game_version >= TR_IV) { ang = (float)(temp1 & 0x0fff); ang *= 360.0 / 4096.0; } else { ang = (float)(temp1 & 0x03ff); ang *= 360.0 / 1024.0; } switch (temp1 & 0xc000) { case 0x4000: // x only rot[0] = ang; rot[1] = 0; rot[2] = 0; vec4_SetTRRotations(bone_tag->qrotate, rot); break; case 0x8000: // y only rot[0] = 0; rot[1] = 0; rot[2] =-ang; vec4_SetTRRotations(bone_tag->qrotate, rot); break; case 0xc000: // z only rot[0] = 0; rot[1] = ang; rot[2] = 0; vec4_SetTRRotations(bone_tag->qrotate, rot); break; default: // all three temp2 = tr->frame_data[frame_offset + l]; rot[0] = (float)((temp1 & 0x3ff0) >> 4); rot[2] =-(float)(((temp1 & 0x000f) << 6) | ((temp2 & 0xfc00) >> 10)); rot[1] = (float)(temp2 & 0x03ff); rot[0] *= 360.0 / 1024.0; rot[1] *= 360.0 / 1024.0; rot[2] *= 360.0 / 1024.0; vec4_SetTRRotations(bone_tag->qrotate, rot); l ++; break; }; break; }; } } } } /* * Animations interpolation to 1/30 sec like in original. Needed for correct state change works. */ SkeletalModel_InterpolateFrames(model); GenerateAnimCommandsTransform(model); /* * state change's loading */ #if LOG_ANIM_DISPATCHES if(model->animation_count > 1) { Sys_DebugLog(LOG_FILENAME, "MODEL[%d], anims = %d", model_num, model->animation_count); } #endif anim = model->animations; for(i=0;i<model->animation_count;i++,anim++) { anim->state_change_count = 0; anim->state_change = NULL; tr_animation = &tr->animations[tr_moveable->animation_index+i]; j = (int)tr_animation->next_animation - (int)tr_moveable->animation_index; j &= 0x7fff; if(j >= 0 && j < model->animation_count) { anim->next_anim = model->animations + j; anim->next_frame = tr_animation->next_frame - tr->animations[tr_animation->next_animation].frame_start; anim->next_frame %= anim->next_anim->frames_count; if(anim->next_frame < 0) { anim->next_frame = 0; } #if LOG_ANIM_DISPATCHES Sys_DebugLog(LOG_FILENAME, "ANIM[%d], next_anim = %d, next_frame = %d", i, anim->next_anim->id, anim->next_frame); #endif } else { anim->next_anim = NULL; anim->next_frame = 0; } anim->state_change_count = 0; anim->state_change = NULL; if((tr_animation->num_state_changes > 0) && (model->animation_count > 1)) { state_change_p sch_p; #if LOG_ANIM_DISPATCHES Sys_DebugLog(LOG_FILENAME, "ANIM[%d], next_anim = %d, next_frame = %d", i, (anim->next_anim)?(anim->next_anim->id):(-1), anim->next_frame); #endif anim->state_change_count = tr_animation->num_state_changes; sch_p = anim->state_change = (state_change_p)malloc(tr_animation->num_state_changes * sizeof(state_change_t)); for(j=0;j<tr_animation->num_state_changes;j++,sch_p++) { tr_state_change_t *tr_sch; tr_sch = &tr->state_changes[j+tr_animation->state_change_offset]; sch_p->id = tr_sch->state_id; sch_p->anim_dispath = NULL; sch_p->anim_dispath_count = 0; for(l=0;l<tr_sch->num_anim_dispatches;l++) { tr_anim_dispatch_t *tr_adisp = &tr->anim_dispatches[tr_sch->anim_dispatch+l]; int next_anim = tr_adisp->next_animation & 0x7fff; int next_anim_ind = next_anim - (tr_moveable->animation_index & 0x7fff); if((next_anim_ind >= 0) &&(next_anim_ind < model->animation_count)) { sch_p->anim_dispath_count++; sch_p->anim_dispath = (anim_dispath_p)realloc(sch_p->anim_dispath, sch_p->anim_dispath_count * sizeof(anim_dispath_t)); anim_dispath_p adsp = sch_p->anim_dispath + sch_p->anim_dispath_count - 1; int next_frames_count = model->animations[next_anim - tr_moveable->animation_index].frames_count; int next_frame = tr_adisp->next_frame - tr->animations[next_anim].frame_start; int low = tr_adisp->low - tr_animation->frame_start; int high = tr_adisp->high - tr_animation->frame_start; adsp->frame_low = low % anim->frames_count; adsp->frame_high = (high - 1) % anim->frames_count; adsp->next_anim = next_anim - tr_moveable->animation_index; adsp->next_frame = next_frame % next_frames_count; #if LOG_ANIM_DISPATCHES Sys_DebugLog(LOG_FILENAME, "anim_disp[%d], frames_count = %d: interval[%d.. %d], next_anim = %d, next_frame = %d", l, anim->frames_count, adsp->frame_low, adsp->frame_high, adsp->next_anim, adsp->next_frame); #endif } } } } } }
ãã§ãã
éªšæ Œã¢ãã«ãæ©èœãå§ãããšããç©çåŠã®ååšãå¿ èŠãšããã¬ããªã³ã°ãšã埩掻ãã«é²ãããšããã§ã«å¯èœã§ããã ããããããããã¯ã«ç²Ÿéããæ¢æã®è£œåã®éžæã«ãã培åºçã«ã¢ãããŒãããããã«ãç¬èªã®ç©çãšã³ãžã³ãäœæããããšã決å®ãããŸããã ãã£ã©ã¯ã¿ãŒã³ã³ãããŒã©ãŒãäœæããããã«æåã«å¿ èŠãªããšã¯ãé«ãã決å®ããããšã§ãã æåã«ãïŒ éå¿ã¢ã«ãŽãªãºã ã«åºã¥ããŠïŒäžè§åœ¢ãšå ç·ã®äº€å·®ã決å®ããé¢æ°ãèšè¿°ãããŸããã ãã®åŸã移åã»ã°ã¡ã³ããäžè§åœ¢ãšçãäžè§åœ¢ãšäžè§åœ¢ã®äº€ç¹ã決å®ãããªã©ã®åºæ¬çãªæ¹æ³ãè¿œå ãããŸããã ãã®ã¢ãããŒãã¯ãã€ã³ãã«ã¹ããŒã¹ã®ç©çãšã³ãžã³ã«åºæã®ãããããããã³ãã«å¹æãïŒé«éã®ãããé«éã®ãªããžã§ã¯ããè¡çªããããšãªãäºãã«é£è¡ã§ããå ŽåïŒã®åºçŸã®å¯èœæ§ãæé€ããããšã«æ³šæããå¿ èŠããããŸãã
ãã®ãããã©ã©ã¯ãããããµã€ãºã®ã¹ãããããã¹ãŠééããŠããã¬ãã«ãé§ãæããŸããããããããè±èœããããšã¯ãããŸããïŒ ãããžã§ã¯ãããã®ãããªç¶æ ã«ãã£ããšããã¢ãããªãŒã»ã«ã ãã¯ãå°ãªããšã誰ãããã¥ãŒã ã¬ã€ããŒã®æåã®éšåã«èå³ãæã£ãŠããã®ã¯ã¯ãŒã«ã ãšç§ã«æžããã ãã®ããã«ããŠããããžã§ã¯ããžã®é¢å¿ãåã³çŸãå§ãããããã§ãéä¿¡ãå§ãŸããŸããã tombraiderforums.comã«ç»é²ããåŸïŒAnatolyã¯ã Tomb raiderã®ç¬¬4éšã®ãšã³ãžã³ãæ¹åãã圌ã®ãããžã§ã¯ãã§ãããªãé·ãéããã«ããŸããïŒã 圌ã®ãããã§ãç§ã®ãšã³ãžã³ãšã³ãŒãã®å€ãã®æ¹åã«é¢ãããããã¯ããã®ãã©ãŒã©ã ã«ç»å ŽããŸããïŒãµãŠã³ããããŒãžã£ãŒãç¶æ å¶åŸ¡ã·ã¹ãã ã®å€æŽïŒä»¥åã¯ã¢ãã¡ãŒã·ã§ã³çªå·ã«ããåãæ¿ãããããçŸåšã¯ç¶æ çªå·ã«ããïŒã ãããžã§ã¯ãã«èå³ã®ãã人ã ã®ååšã¯ããããžã§ã¯ããéçºããåæ©ä»ãã«ãªããŸãã
ç©çåŠ+ã¬ã³ãã©ãŒæé©å
ç©çåŠã䜿çšããæé©åãäžååã§ãã£ãŠããfpsã¯ããã€ãã®å Žæã§äœäžãå§ããŸããã ããŸããŸãªãªãŒãã³ãœãŒã¹ã®ç©çãšã³ãžã³ãé·ãééžã¶ããšã§ã 匟䞞ãéžã°ããŸããã æåã«ããããšã¯ãéšå±ã亀差ããå Žåã«è¡çªãã£ã«ã¿ãŒãè¿œå ããããšã§ããã å®éã«ã¯ãå ã®ã¬ãã«ã®èšèšã§ã¯ã1ã€ã®å Žæã§2ã€ä»¥äžã®å®å šã«ç°ãªãéšå±ã®äº€å·®ãèš±å¯ãããŸããã1ã€ã®éšå±ã®ãªããžã§ã¯ãã¯å¥ã®éšå±ã®ãªããžã§ã¯ãã«åœ±é¿ãäžããŸããã ã¬ã³ããªã³ã°ãšåæ§ã çŸåšãç§ã¯ãã£ã©ã¯ã¿ãŒã®ã³ã³ãããŒã©ãŒã«æããã¯ããããšããŠããŸãïŒå£ãééããå¯èœæ§ãæé€ãïŒå£ã«ç¹ãæ¥ããå€ãã®ã¢ãã¡ãŒã·ã§ã³ã§çºçããŸãïŒãå£ã倩äºã«ã¯ãªããã³ã°ãçºçããå Žåã®ãã£ã©ã¯ã¿ãŒã®åå¿ãšåäœãå®äºããŸãã
OpenGLã«æ»ããŸãã æåããšã³ãžã³ã§ã¯ã glVertex3fv ïŒ...ïŒãªã©ã䜿çšããŠããªãŽã³ãæç»ãããŸããã ãã®ã¢ãããŒãã®ããã©ãŒãã³ã¹ãšãšã³ãžã³ã®é床ã«ã€ããŠ1ã€èšããããšããããŸããããã¯ãããŸããã ãã®ããã VBO ïŒé ç¹ãããã¡ãŒãªããžã§ã¯ãïŒã«é¢é£ããéšåã調ã¹ãåŸãæé©åãè¡ããããªãŽã³ã®é ç¹ã®ããŒã¿ããããªã¡ã¢ãªã«ã§ããã ãæ ŒçŽããäžåºŠã«ã¡ãã·ã¥ãæç»ãå§ããŸããã é床ãèããåäžããŸããã ãã ãã1ã€ã®ã¡ãã·ã¥ãã¯ã¹ãã£ãç°ãªããã¯ã»ã«é åã«ããå¯èœæ§ããããããOpenGLãã¯ã¹ãã£ã®åãæ¿ãã¯å¿ èŠä»¥äžã«é »ç¹ã«è¡ãããå€ãã®ç°ãªããªããžã§ã¯ãã®ãã¯ã¹ãã£ããã¯ã»ã«ã®1ã€ã®é åã«ä¿åã§ãããšããäºå®ã«ãããã¢ã³ããšã€ãªã¢ã·ã³ã°ããªã³ã«ãããšãã¢ãŒãã£ãã¡ã¯ãããäœæãããŸããã tombraiderforums.comã® Cochraneã¯ã¬ã³ãã©ãŒã®æé©åãåŒãåãããã¯ã¹ãã£éã®å¢çç·ãæã€ãã¯ã¹ãã£ã¢ãã©ã¹ãäœæããŸããã ãã®é©æ°ã«ããããã¹ãŠã®ã¬ãã«ã®ãã¯ã¹ãã£ã1ã2åã®OpenGLãã¯ã¹ãã£ã«ä¿åãããã¹ã ãŒãžã³ã°ã«ãã£ãŠãã¢ãŒãã£ãã¡ã¯ããã衚瀺ãããããšã¯ãããŸããã ããã«ã圌ã¯MacOSã«ç§»æ€ããŸããã
ãšã³ãžã³ã«äœãã©ã®ããã«åãçµããã®ã¢ã€ãã¢ããªãã£ããšããã³ãŒãã®ãšã©ãŒãæ¢ãããã®æ§é ãä¿®æ£ããæ¥ç¶ãããã©ã€ãã©ãªãå€æŽããŸããã ãããã£ãŠããåé 眮ãã¯SDL1ããSDL2ã«ã freetype1 + glttããfreetype2 + ftglã«å®è¡ãããŸãã ã åæ§ã«ã slerpçé¢è£éã䜿çšããŠãã¢ãã¡ãŒã·ã§ã³ã«ã¢ã³ããšã€ãªã¢ã¹ãè¿œå ãããšããã¢ã€ãã¢ãæãã€ããŸããã ããã§è¿œå ãããããšã¯ãç¹ã«ãã¢ãŒããïŒasinãacosãatanãªã©ïŒã«é¢ããŠã¯ãæ°åŠã¢ã«ãŽãªãºã ã«æ³šæããŠãã ããããµã€ã³ã倱ããšãã¹ã±ã«ãã³ãæªãã§ãããããã©ãŒãã¬ãŒã ãå€ããªããŸãã bulletã®ãœãŒã¹ã³ãŒãã§slerpã®å®è£ ã確èªããããšããå§ãããŸãã ã¢ã³ããšã€ãªã¢ã¹ãè¿œå ããåŸãæ»ããã§ãªãã¢ãã¡ãŒã·ã§ã³ãèŠãããšãã§ããªããªããŸããã ããã«ã Tomb raiderã§ããããµãŠã³ããããŒãããŠåçããå¿ èŠããããèŽåœçãªæ²é»ã®äžã§ã¬ãã«ãå®è¡ããããšã¯ããŸããããŸããã
é³ãè¿œå ãã
ãµãŠã³ãã䜿çšããã«ã¯ã SDLAudio + SDLMixerã䜿çšããã ãã§ã¯å®å šã«äžååã§ããããªãŒãã£ãªã¹ããªãŒã å€æã¢ã«ãŽãªãºã ã«å ¥ãããã€ã¯ãäœæããŠãšãã§ã¯ããäœæããããšã¯æªãèãã§ãã Anatolyãšçžè«ããåŸã OpenALã䜿çšããããšã決å®ãããŸããã ã§ããã ãå€ãã®ãã©ãããã©ãŒã åºæã®ã³ãŒããSDLã«è»¢éããããšããäºå®ã«å°ãããã®ã§ã OpenALã® SDL_backendãæžãããšã»ã©è¯ããã®ã¯æãã€ããŸããã§ãããããããããã¯æ©èœããããŒã«ããšã³ãžã³ã«è¿œå ããã¢ãããªãŒã¯å¿ èŠã«å¿ããŠãå¿ èŠã«å¿ããŠããããŠå¿ èŠãªå¹æã§å šå¡ã«ãã¬ã€ãããŸããã
ãããŠä»ãã²ãŒã äžçã®ããããçš®é¡ã®ã¬ããŒããã©ããããã®ä»ã®ããªã¬ãŒã埩掻ãããæãæ¥ãŸãããå®éãããã§ã®éçºã¯ããžãã¯ã«åŸã£ãŠè¡ãããŸãããäœããå®è£ ããå¿ èŠããããŸããããã«å¿ èŠãªããŒã«ããããã®å®è£ æ¹æ³ãã¹ã¯ãªããã«äœ¿çšãããäž»ãªæ©èœã¯ãæ°å€IDã§ãªããžã§ã¯ããžã®ãã€ã³ã¿ãŒãååŸããããšã§ããããã«ãããLUAé¢æ°ã¯ãã¹ãŠã®å¿ èŠãªãªããžã§ã¯ããåŠçã§ããŸãããªããžã§ã¯ããåçã«è¿œå ããã³åé€ããIDã§ãªããžã§ã¯ãã«ãã°ããã¢ã¯ã»ã¹ããããã«ãèµ€é»æšã䜿çšããŸãããçè«çã«ã¯ãããŒãã«ã®ããã·ã¥ã䜿çšã§ããŸãããå人çãªå¥œã¿ã¯ããããããã§ããŸããããŸããã
ãã®çµæãã¹ã¯ãªããã·ã¹ãã ã«ããããªããžã§ã¯ããšã¢ãã¡ãŒã·ã§ã³ã䜿çšããã»ãŒãã¹ãŠã®æäœã®å®è¡ãã¿ã¹ã¯ïŒããã³ãããã«åºã¥ãã¿ã€ããŒïŒã®äœæããªããžã§ã¯ãã®éžæãããªã声ãšãã¿ã³ã®æŒäžããã¢ã®ééãªã©ãå¯èœã«ãªããŸãããtombraiderforums.comã³ãã¥ããã£ã®äººã ã®åªåã®ãããã§ãããã¬ãã«ããå¥ã®ã¬ãã«ãžã®ç§»åãå¿ èŠãªã¹ã¯ãªãããšã¹ã¯ãªãŒã³ã»ãŒããŒã®ããŒããå æºã«é¢ããæ å ±ã®ããŒããOS Lunuxã§ãã«ãããããã®é ç¹ã«ã©ãŒèª¿æŽãšcmakeã¹ã¯ãªããã«åºã¥ãã·ã³ãã«ãªã©ã€ããããã®å®è£ ãæ åœããgameflow_managerãè¿œå ãããŸããã
ããšãã
æåŸã«ããµãŒãããŒãã£ã®ãªãœãŒã¹ã䜿çšãããšããã¹ããç°¡åã«ãªããã³ã³ãã³ãã®äœæã«è² æ ããããå¿ èŠããããŸããããããã«ãããšã³ãžã³ã®ã¢ãŒããã¯ãã£ã«å¶éã課ãããããèµ·åæã«ãã©ãŒããããå€æããŠã²ã©ãæŸèæãäœããªãããã«ããå¿ èŠãããããšã«æ³šæããŠãã ããã²ãŒã ãšã³ãžã³ããããŠããªãªãžãã«ã®ãã¥ãŒã ã¬ã€ããŒã«ã¯å€ãã®æŸèæããããŸãããããžã§ã¯ãã®
ä»åŸã®èšç»ã¯åçŽã§ãã1ïŒæ¢åã®ãã°ãç¹ã«ç©çåŠã®ãã°ãä¿®æ£ãããã£ã©ã¯ã¿ãŒã³ã³ãããŒã©ãŒã®æ©èœãæ¡åŒµããŸãã2ïŒãããäžã®æµãã埩掻ããããAIãšæŠåšãè¿œå ããŸãã3ïŒã¡ãã·ã¥ãåãæ¿ããããã®éªšæ Œã¢ãã«ã®ã¢ãã¡ãŒã·ã§ã³ç®¡çã·ã¹ãã ãæ¡åŒµããŸãã
4ïŒã¹ã¯ãªããã·ã¹ãã ã®æ©èœãæ¡åŒµããããŒã¬ãã«ã®ã¹ã¯ãªãããäœæããŠãéåžžã®ã²ãŒã ãäœéšã§ããããã«ããŸãã
5ïŒã²ãŒã å ã®ã°ã©ãã£ãã¯ã¹ãæ¹åããå¹æãè¿œå ããŸãããããã§ã¯ããè³æ Œã®ããOpenGLããã°ã©ããŒã®å©ããæåŸ ããŠããŸãã
æåŸã«ããšã³ãžã³ã®äŸãå«ãããã€ãã®ãããªïŒ
ãæž èŽããããšãããããŸããïŒ