mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-21 04:11:53 +02:00
23
src/format.h
23
src/format.h
@@ -2499,16 +2499,6 @@ namespace TR {
|
|||||||
} inv;
|
} inv;
|
||||||
} extra;
|
} extra;
|
||||||
|
|
||||||
struct TPAL {
|
|
||||||
uint8 data[3];
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32 tpalCount;
|
|
||||||
TPAL *tpal;
|
|
||||||
|
|
||||||
int32 spalCount;
|
|
||||||
uint16 *spal;
|
|
||||||
|
|
||||||
uint32 tsubCount;
|
uint32 tsubCount;
|
||||||
uint8 *tsub;
|
uint8 *tsub;
|
||||||
|
|
||||||
@@ -2971,8 +2961,6 @@ namespace TR {
|
|||||||
delete[] soundOffsets;
|
delete[] soundOffsets;
|
||||||
delete[] soundSize;
|
delete[] soundSize;
|
||||||
|
|
||||||
delete[] spal;
|
|
||||||
delete[] tpal;
|
|
||||||
delete[] tsub;
|
delete[] tsub;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3032,17 +3020,12 @@ namespace TR {
|
|||||||
break;
|
break;
|
||||||
case CHUNK("ROOMTPAL") : {
|
case CHUNK("ROOMTPAL") : {
|
||||||
ASSERTV(stream.readBE32() == 0x00000003);
|
ASSERTV(stream.readBE32() == 0x00000003);
|
||||||
tpalCount = stream.readBE32();
|
stream.seek(stream.readBE32() * 3);
|
||||||
tpal = new TPAL[tpalCount];
|
|
||||||
stream.raw(tpal, sizeof(TPAL) * tpalCount);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CHUNK("ROOMSPAL") : {
|
case CHUNK("ROOMSPAL") : {
|
||||||
ASSERTV(stream.readLE32() == 0x02000000);
|
ASSERTV(stream.readLE32() == 0x02000000);
|
||||||
spalCount = stream.readBE32();
|
stream.seek(stream.readBE32() * 2);
|
||||||
spal = new uint16[spalCount];
|
|
||||||
for (int i = 0; i < spalCount; i++)
|
|
||||||
spal[i] = stream.readBE16();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CHUNK("ROOMDATA") :
|
case CHUNK("ROOMDATA") :
|
||||||
@@ -3411,8 +3394,6 @@ namespace TR {
|
|||||||
case CHUNK("ROOMEND ") :
|
case CHUNK("ROOMEND ") :
|
||||||
ASSERTV(stream.readBE32() == 0x00000000);
|
ASSERTV(stream.readBE32() == 0x00000000);
|
||||||
ASSERTV(stream.readBE32() == 0x00000000);
|
ASSERTV(stream.readBE32() == 0x00000000);
|
||||||
LOG("tpalCount = %d\n", tpalCount);
|
|
||||||
LOG("spalCount = %d\n", spalCount);
|
|
||||||
prepare();
|
prepare();
|
||||||
break;
|
break;
|
||||||
// SAD
|
// SAD
|
||||||
|
@@ -290,8 +290,8 @@ namespace TR {
|
|||||||
// TITLE
|
// TITLE
|
||||||
case 585648 : // PSX JAP
|
case 585648 : // PSX JAP
|
||||||
case 508614 : version = VER_TR1_PSX;
|
case 508614 : version = VER_TR1_PSX;
|
||||||
//case 320412 : // PC JAP
|
|
||||||
case 5148 : // SAT
|
case 5148 : // SAT
|
||||||
|
case 320412 : // PC JAP
|
||||||
case 334874 :
|
case 334874 :
|
||||||
case 316138 :
|
case 316138 :
|
||||||
case 316460 : return LVL_TR1_TITLE;
|
case 316460 : return LVL_TR1_TITLE;
|
||||||
@@ -305,7 +305,7 @@ namespace TR {
|
|||||||
// LEVEL1
|
// LEVEL1
|
||||||
case 1667568 : // PSX JAP
|
case 1667568 : // PSX JAP
|
||||||
case 1448896 : version = VER_TR1_PSX;
|
case 1448896 : version = VER_TR1_PSX;
|
||||||
case 497656 :
|
case 497656 : // SAT
|
||||||
case 2540906 : // PC JAP
|
case 2540906 : // PC JAP
|
||||||
case 2533312 :
|
case 2533312 :
|
||||||
case 2533634 : return LVL_TR1_1;
|
case 2533634 : return LVL_TR1_1;
|
||||||
@@ -313,96 +313,114 @@ namespace TR {
|
|||||||
case 2873406 : isDemoLevel = true; return LVL_TR1_2;
|
case 2873406 : isDemoLevel = true; return LVL_TR1_2;
|
||||||
case 1766352 : // PSX JAP
|
case 1766352 : // PSX JAP
|
||||||
case 1535734 : version = VER_TR1_PSX;
|
case 1535734 : version = VER_TR1_PSX;
|
||||||
|
case 532250 : // SAT
|
||||||
case 2880722 : // PC JAP
|
case 2880722 : // PC JAP
|
||||||
case 2873128 :
|
case 2873128 :
|
||||||
case 2873450 : return LVL_TR1_2;
|
case 2873450 : return LVL_TR1_2;
|
||||||
// LEVEL3A
|
// LEVEL3A
|
||||||
case 1876896 : // PSX JAP
|
case 1876896 : // PSX JAP
|
||||||
case 1630560 : version = VER_TR1_PSX;
|
case 1630560 : version = VER_TR1_PSX;
|
||||||
|
case 547782 : // SAT
|
||||||
case 2942002 : // PC JAP
|
case 2942002 : // PC JAP
|
||||||
case 2934408 :
|
case 2934408 :
|
||||||
case 2934730 : return LVL_TR1_3A;
|
case 2934730 : return LVL_TR1_3A;
|
||||||
// LEVEL3B
|
// LEVEL3B
|
||||||
case 1510414 : // PSX JAP
|
case 1510414 : // PSX JAP
|
||||||
case 1506614 : version = VER_TR1_PSX;
|
case 1506614 : version = VER_TR1_PSX;
|
||||||
|
case 310960 : // SAT
|
||||||
case 2745530 : // PC JAP
|
case 2745530 : // PC JAP
|
||||||
case 2737936 :
|
case 2737936 :
|
||||||
case 2738258 : return LVL_TR1_3B;
|
case 2738258 : return LVL_TR1_3B;
|
||||||
// CUT1
|
// CUT1
|
||||||
case 722402 : version = VER_TR1_PSX;
|
case 722402 : version = VER_TR1_PSX;
|
||||||
|
case 142116 : // SAT
|
||||||
case 599840 : return LVL_TR1_CUT_1;
|
case 599840 : return LVL_TR1_CUT_1;
|
||||||
// LEVEL4
|
// LEVEL4
|
||||||
case 1624130 : // PSX JAP
|
case 1624130 : // PSX JAP
|
||||||
case 1621970 : version = VER_TR1_PSX;
|
case 1621970 : version = VER_TR1_PSX;
|
||||||
|
case 440612 : // SAT
|
||||||
case 3038144 : // PC JAP
|
case 3038144 : // PC JAP
|
||||||
case 3030550 :
|
case 3030550 :
|
||||||
case 3030872 : return LVL_TR1_4;
|
case 3030872 : return LVL_TR1_4;
|
||||||
// LEVEL5
|
// LEVEL5
|
||||||
case 1588102 : // PSX JAP
|
case 1588102 : // PSX JAP
|
||||||
case 1585942 : version = VER_TR1_PSX;
|
case 1585942 : version = VER_TR1_PSX;
|
||||||
|
case 389996 : // SAT
|
||||||
case 2725812 : // PC JAP
|
case 2725812 : // PC JAP
|
||||||
case 2718218 :
|
case 2718218 :
|
||||||
case 2718540 : return LVL_TR1_5;
|
case 2718540 : return LVL_TR1_5;
|
||||||
// LEVEL6
|
// LEVEL6
|
||||||
case 1710624 : // PSX JAP
|
case 1710624 : // PSX JAP
|
||||||
case 1708464 : version = VER_TR1_PSX;
|
case 1708464 : version = VER_TR1_PSX;
|
||||||
|
case 573506 : // SAT
|
||||||
case 3147184 : // PC JAP
|
case 3147184 : // PC JAP
|
||||||
case 3139590 :
|
case 3139590 :
|
||||||
case 3074376 : return LVL_TR1_6;
|
case 3074376 : return LVL_TR1_6;
|
||||||
// LEVEL7A
|
// LEVEL7A
|
||||||
case 1698824 : // PSX JAP
|
case 1698824 : // PSX JAP
|
||||||
case 1696664 : version = VER_TR1_PSX;
|
case 1696664 : version = VER_TR1_PSX;
|
||||||
|
case 581416 : // SAT
|
||||||
case 2824884 : // PC JAP
|
case 2824884 : // PC JAP
|
||||||
case 2817290 :
|
case 2817290 :
|
||||||
case 2817612 : return LVL_TR1_7A;
|
case 2817612 : return LVL_TR1_7A;
|
||||||
// LEVEL7B
|
// LEVEL7B
|
||||||
case 1735434 : // PSX JAP
|
case 1735434 : // PSX JAP
|
||||||
case 1733274 : version = VER_TR1_PSX;
|
case 1733274 : version = VER_TR1_PSX;
|
||||||
|
case 596416 : // SAT
|
||||||
case 3603912 : // PC JAP
|
case 3603912 : // PC JAP
|
||||||
case 3388774 :
|
case 3388774 :
|
||||||
case 3389096 : return LVL_TR1_7B;
|
case 3389096 : return LVL_TR1_7B;
|
||||||
// CUT2
|
// CUT2
|
||||||
case 542960 : version = VER_TR1_PSX;
|
case 542960 : version = VER_TR1_PSX;
|
||||||
|
case 70860 : // SAT
|
||||||
case 354320 : return LVL_TR1_CUT_2;
|
case 354320 : return LVL_TR1_CUT_2;
|
||||||
// LEVEL8A
|
// LEVEL8A
|
||||||
case 1565494 : // PSX JAP
|
case 1565494 : // PSX JAP
|
||||||
case 1563356 : version = VER_TR1_PSX;
|
case 1563356 : version = VER_TR1_PSX;
|
||||||
|
case 592188 : // SAT
|
||||||
case 2887836 : // PC JAP
|
case 2887836 : // PC JAP
|
||||||
case 2880242 :
|
case 2880242 :
|
||||||
case 2880564 : return LVL_TR1_8A;
|
case 2880564 : return LVL_TR1_8A;
|
||||||
// LEVEL8B
|
// LEVEL8B
|
||||||
case 1567790 : // PSX JAP
|
case 1567790 : // PSX JAP
|
||||||
case 1565630 : version = VER_TR1_PSX;
|
case 1565630 : version = VER_TR1_PSX;
|
||||||
|
case 599928 : // SAT
|
||||||
case 2894028 : // PC JAP
|
case 2894028 : // PC JAP
|
||||||
case 2886434 :
|
case 2886434 :
|
||||||
case 2886756 : return LVL_TR1_8B;
|
case 2886756 : return LVL_TR1_8B;
|
||||||
// LEVEL8C
|
// LEVEL8C
|
||||||
case 1621520 : // PSX JAP
|
case 1621520 : // PSX JAP
|
||||||
case 1619360 : version = VER_TR1_PSX;
|
case 1619360 : version = VER_TR1_PSX;
|
||||||
|
case 536950 : // SAT
|
||||||
case 3072066 : // PC JAP
|
case 3072066 : // PC JAP
|
||||||
case 3105128 :
|
case 3105128 :
|
||||||
case 3105450 : return LVL_TR1_8C;
|
case 3105450 : return LVL_TR1_8C;
|
||||||
// LEVEL10A
|
// LEVEL10A
|
||||||
case 1680146 : // PSX JAP
|
case 1680146 : // PSX JAP
|
||||||
case 1678018 : version = VER_TR1_PSX;
|
case 1678018 : version = VER_TR1_PSX;
|
||||||
|
case 569856 : // SAT
|
||||||
case 3270372 : // PC JAP
|
case 3270372 : // PC JAP
|
||||||
case 3223816 :
|
case 3223816 :
|
||||||
case 3224138 : return LVL_TR1_10A;
|
case 3224138 : return LVL_TR1_10A;
|
||||||
// CUT3
|
// CUT3
|
||||||
case 636660 : version = VER_TR1_PSX;
|
case 636660 : version = VER_TR1_PSX;
|
||||||
|
case 210134 : // SAT
|
||||||
case 512104 : return LVL_TR1_CUT_3;
|
case 512104 : return LVL_TR1_CUT_3;
|
||||||
// LEVEL10B
|
// LEVEL10B
|
||||||
case 1688908 : // PSX JAP
|
case 1688908 : // PSX JAP
|
||||||
case 1686748 : version = VER_TR1_PSX;
|
case 1686748 : version = VER_TR1_PSX;
|
||||||
|
case 525646 : // SAT
|
||||||
case 3101614 : // PC JAP
|
case 3101614 : // PC JAP
|
||||||
case 3094342 :
|
case 3094342 :
|
||||||
case 3094020 : return LVL_TR1_10B;
|
case 3094020 : return LVL_TR1_10B;
|
||||||
// CUT4
|
// CUT4
|
||||||
case 940398 : version = VER_TR1_PSX;
|
case 940398 : version = VER_TR1_PSX;
|
||||||
|
case 167188 : // SAT
|
||||||
case 879582 : return LVL_TR1_CUT_4;
|
case 879582 : return LVL_TR1_CUT_4;
|
||||||
// LEVEL10C
|
// LEVEL10C
|
||||||
case 1816438 : // PSX JAP
|
case 1816438 : // PSX JAP
|
||||||
case 1814278 : version = VER_TR1_PSX;
|
case 1814278 : version = VER_TR1_PSX;
|
||||||
|
case 418170 : // SAT
|
||||||
case 3533814 : // PC JAP
|
case 3533814 : // PC JAP
|
||||||
case 3531702 :
|
case 3531702 :
|
||||||
case 3532024 : return LVL_TR1_10C;
|
case 3532024 : return LVL_TR1_10C;
|
||||||
@@ -1095,6 +1113,7 @@ namespace TR {
|
|||||||
if (version & VER_TR1) {
|
if (version & VER_TR1) {
|
||||||
CHECK_FILE("FMV/CORELOGO.FMV");
|
CHECK_FILE("FMV/CORELOGO.FMV");
|
||||||
CHECK_FILE("FMV/CORE.RPL");
|
CHECK_FILE("FMV/CORE.RPL");
|
||||||
|
CHECK_FILE("FMV/CORELOGO.CPK");
|
||||||
CHECK_FILE("video/1/CORELOGO.FMV");
|
CHECK_FILE("video/1/CORELOGO.FMV");
|
||||||
CHECK_FILE("video/1/CORE.RPL");
|
CHECK_FILE("video/1/CORE.RPL");
|
||||||
}
|
}
|
||||||
@@ -1122,56 +1141,74 @@ namespace TR {
|
|||||||
case LVL_TR1_TITLE :
|
case LVL_TR1_TITLE :
|
||||||
CHECK_FILE("FMV/CAFE.FMV");
|
CHECK_FILE("FMV/CAFE.FMV");
|
||||||
CHECK_FILE("FMV/CAFE.RPL");
|
CHECK_FILE("FMV/CAFE.RPL");
|
||||||
|
CHECK_FILE("FMV/CAFE.CPK");
|
||||||
CHECK_FILE("video/1/CAFE.FMV");
|
CHECK_FILE("video/1/CAFE.FMV");
|
||||||
CHECK_FILE("video/1/CAFE.RPL");
|
CHECK_FILE("video/1/CAFE.RPL");
|
||||||
|
CHECK_FILE("video/1/CAFE.CPK");
|
||||||
break;
|
break;
|
||||||
case LVL_TR1_GYM :
|
case LVL_TR1_GYM :
|
||||||
CHECK_FILE("FMV/MANSION.FMV");
|
CHECK_FILE("FMV/MANSION.FMV");
|
||||||
CHECK_FILE("FMV/MANSION.RPL");
|
CHECK_FILE("FMV/MANSION.RPL");
|
||||||
|
CHECK_FILE("FMV/MANSION.CPK");
|
||||||
CHECK_FILE("video/1/MANSION.FMV");
|
CHECK_FILE("video/1/MANSION.FMV");
|
||||||
CHECK_FILE("video/1/MANSION.RPL");
|
CHECK_FILE("video/1/MANSION.RPL");
|
||||||
|
CHECK_FILE("video/1/MANSION.CPK");
|
||||||
break;
|
break;
|
||||||
case LVL_TR1_1 :
|
case LVL_TR1_1 :
|
||||||
CHECK_FILE("FMV/SNOW.FMV");
|
CHECK_FILE("FMV/SNOW.FMV");
|
||||||
CHECK_FILE("FMV/SNOW.RPL");
|
CHECK_FILE("FMV/SNOW.RPL");
|
||||||
|
CHECK_FILE("FMV/SNOW.CPK");
|
||||||
CHECK_FILE("video/1/SNOW.FMV");
|
CHECK_FILE("video/1/SNOW.FMV");
|
||||||
CHECK_FILE("video/1/SNOW.RPL");
|
CHECK_FILE("video/1/SNOW.RPL");
|
||||||
|
CHECK_FILE("video/1/SNOW.CPK");
|
||||||
break;
|
break;
|
||||||
case LVL_TR1_4 :
|
case LVL_TR1_4 :
|
||||||
CHECK_FILE("FMV/LIFT.FMV");
|
CHECK_FILE("FMV/LIFT.FMV");
|
||||||
CHECK_FILE("FMV/LIFT.RPL");
|
CHECK_FILE("FMV/LIFT.RPL");
|
||||||
|
CHECK_FILE("FMV/LIFT.CPK");
|
||||||
CHECK_FILE("video/1/LIFT.FMV");
|
CHECK_FILE("video/1/LIFT.FMV");
|
||||||
CHECK_FILE("video/1/LIFT.RPL");
|
CHECK_FILE("video/1/LIFT.RPL");
|
||||||
|
CHECK_FILE("video/1/LIFT.CPK");
|
||||||
break;
|
break;
|
||||||
case LVL_TR1_8A :
|
case LVL_TR1_8A :
|
||||||
CHECK_FILE("FMV/VISION.FMV");
|
CHECK_FILE("FMV/VISION.FMV");
|
||||||
CHECK_FILE("FMV/VISION.RPL");
|
CHECK_FILE("FMV/VISION.RPL");
|
||||||
|
CHECK_FILE("FMV/VISION.CPK");
|
||||||
CHECK_FILE("video/1/VISION.FMV");
|
CHECK_FILE("video/1/VISION.FMV");
|
||||||
CHECK_FILE("video/1/VISION.RPL");
|
CHECK_FILE("video/1/VISION.RPL");
|
||||||
|
CHECK_FILE("video/1/VISION.CPK");
|
||||||
break;
|
break;
|
||||||
case LVL_TR1_10A :
|
case LVL_TR1_10A :
|
||||||
CHECK_FILE("FMV/CANYON.FMV");
|
CHECK_FILE("FMV/CANYON.FMV");
|
||||||
CHECK_FILE("FMV/CANYON.RPL");
|
CHECK_FILE("FMV/CANYON.RPL");
|
||||||
|
CHECK_FILE("FMV/CANYON.CPK");
|
||||||
CHECK_FILE("video/1/CANYON.FMV");
|
CHECK_FILE("video/1/CANYON.FMV");
|
||||||
CHECK_FILE("video/1/CANYON.RPL");
|
CHECK_FILE("video/1/CANYON.RPL");
|
||||||
|
CHECK_FILE("video/1/CANYON.CPK");
|
||||||
break;
|
break;
|
||||||
case LVL_TR1_10B :
|
case LVL_TR1_10B :
|
||||||
CHECK_FILE("FMV/PYRAMID.FMV");
|
CHECK_FILE("FMV/PYRAMID.FMV");
|
||||||
CHECK_FILE("FMV/PYRAMID.RPL");
|
CHECK_FILE("FMV/PYRAMID.RPL");
|
||||||
|
CHECK_FILE("FMV/PYRAMID.CPK");
|
||||||
CHECK_FILE("video/1/PYRAMID.FMV");
|
CHECK_FILE("video/1/PYRAMID.FMV");
|
||||||
CHECK_FILE("video/1/PYRAMID.RPL");
|
CHECK_FILE("video/1/PYRAMID.RPL");
|
||||||
|
CHECK_FILE("video/1/PYRAMID.CPK");
|
||||||
break;
|
break;
|
||||||
case LVL_TR1_CUT_4 :
|
case LVL_TR1_CUT_4 :
|
||||||
CHECK_FILE("FMV/PRISON.FMV");
|
CHECK_FILE("FMV/PRISON.FMV");
|
||||||
CHECK_FILE("FMV/PRISON.RPL");
|
CHECK_FILE("FMV/PRISON.RPL");
|
||||||
|
CHECK_FILE("FMV/PRISON.CPK");
|
||||||
CHECK_FILE("video/1/PRISON.FMV");
|
CHECK_FILE("video/1/PRISON.FMV");
|
||||||
CHECK_FILE("video/1/PRISON.RPL");
|
CHECK_FILE("video/1/PRISON.RPL");
|
||||||
|
CHECK_FILE("video/1/PRISON.CPK");
|
||||||
break;
|
break;
|
||||||
case LVL_TR1_EGYPT :
|
case LVL_TR1_EGYPT :
|
||||||
CHECK_FILE("FMV/END.FMV");
|
CHECK_FILE("FMV/END.FMV");
|
||||||
CHECK_FILE("FMV/END.RPL");
|
CHECK_FILE("FMV/END.RPL");
|
||||||
|
CHECK_FILE("FMV/END.CPK");
|
||||||
CHECK_FILE("video/1/END.FMV");
|
CHECK_FILE("video/1/END.FMV");
|
||||||
CHECK_FILE("video/1/END.RPL");
|
CHECK_FILE("video/1/END.RPL");
|
||||||
|
CHECK_FILE("video/1/END.CPK");
|
||||||
break;
|
break;
|
||||||
// TR2
|
// TR2
|
||||||
case LVL_TR2_TITLE :
|
case LVL_TR2_TITLE :
|
||||||
|
22
src/utils.h
22
src/utils.h
@@ -1650,17 +1650,21 @@ struct Array {
|
|||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int push(const T &item) {
|
void reserve(int capacity) {
|
||||||
if (!items)
|
this->capacity = capacity;
|
||||||
items = (T*)malloc(capacity * sizeof(T));
|
|
||||||
|
|
||||||
if (length == capacity) {
|
|
||||||
capacity += capacity + capacity / 2;
|
|
||||||
if (items)
|
if (items)
|
||||||
items = (T*)realloc(items, capacity * sizeof(T));
|
items = (T*)realloc(items, capacity * sizeof(T));
|
||||||
else
|
else
|
||||||
items = (T*)malloc(capacity * sizeof(T));
|
items = (T*)malloc(capacity * sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int push(const T &item) {
|
||||||
|
if (!items)
|
||||||
|
items = (T*)malloc(capacity * sizeof(T));
|
||||||
|
|
||||||
|
if (length == capacity)
|
||||||
|
reserve(capacity + capacity / 2);
|
||||||
|
|
||||||
items[length] = item;
|
items[length] = item;
|
||||||
return length++;
|
return length++;
|
||||||
}
|
}
|
||||||
@@ -1681,6 +1685,12 @@ struct Array {
|
|||||||
items[i] = items[i + 1];
|
items[i] = items[i + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resize(int length) {
|
||||||
|
if (capacity < length)
|
||||||
|
reserve(length);
|
||||||
|
this->length = length;
|
||||||
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
length = 0;
|
length = 0;
|
||||||
free(items);
|
free(items);
|
||||||
|
161
src/video.h
161
src/video.h
@@ -1131,6 +1131,156 @@ struct Video {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// based on https://wiki.multimedia.cx/index.php/Sega_FILM
|
||||||
|
struct Cinepak : Decoder {
|
||||||
|
|
||||||
|
struct Chunk {
|
||||||
|
int offset;
|
||||||
|
int size;
|
||||||
|
uint32 info[2];
|
||||||
|
} *chunks;
|
||||||
|
|
||||||
|
int chunksCount;
|
||||||
|
int audioChunkIndex;
|
||||||
|
int audioChunkPos;
|
||||||
|
Array<Sound::Frame> audioChunkFrames;
|
||||||
|
|
||||||
|
int videoChunkIndex;
|
||||||
|
int videoChunkPos;
|
||||||
|
Array<uint8> videoChunkData;
|
||||||
|
|
||||||
|
Cinepak(Stream *stream) : Decoder(stream), chunks(NULL), audioChunkIndex(-1), audioChunkPos(0), videoChunkIndex(-1), videoChunkPos(0) {
|
||||||
|
ASSERTV(stream->readLE32() == FOURCC("FILM"));
|
||||||
|
int sampleOffset = stream->readBE32();
|
||||||
|
stream->seek(4); // skip version 1.06
|
||||||
|
stream->seek(4); // skip reserved
|
||||||
|
ASSERTV(stream->readLE32() == FOURCC("FDSC"));
|
||||||
|
ASSERTV(stream->readBE32() == 32);
|
||||||
|
ASSERTV(stream->readLE32() == FOURCC("cvid"));
|
||||||
|
height = stream->readBE32();
|
||||||
|
width = stream->readBE32();
|
||||||
|
ASSERTV(stream->read() == 24);
|
||||||
|
channels = stream->read();
|
||||||
|
ASSERT(channels == 2);
|
||||||
|
ASSERTV(stream->read() == 16);
|
||||||
|
ASSERTV(stream->read() == 0);
|
||||||
|
freq = stream->readBE16();
|
||||||
|
ASSERT(freq == 22254);
|
||||||
|
|
||||||
|
stream->seek(6);
|
||||||
|
ASSERTV(stream->readLE32() == FOURCC("STAB"));
|
||||||
|
stream->seek(4); // skip STAB length
|
||||||
|
fps = stream->readBE32() / 2;
|
||||||
|
chunksCount = stream->readBE32();
|
||||||
|
chunks = new Chunk[chunksCount];
|
||||||
|
for (int i = 0; i < chunksCount; i++) {
|
||||||
|
Chunk &c = chunks[i];
|
||||||
|
c.offset = stream->readBE32() + sampleOffset;
|
||||||
|
c.size = stream->readBE32();
|
||||||
|
c.info[0] = stream->readBE32();
|
||||||
|
c.info[1] = stream->readBE32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Cinepak() {
|
||||||
|
delete[] chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool decodeVideo(Color32 *pixels) {
|
||||||
|
if (audioChunkIndex >= chunksCount)
|
||||||
|
return false;
|
||||||
|
/*
|
||||||
|
// TODO: sega cinepak film decoder
|
||||||
|
// get next audio chunk
|
||||||
|
if (videoChunkPos >= videoChunkData.length) {
|
||||||
|
videoChunkPos = 0;
|
||||||
|
|
||||||
|
while (++videoChunkIndex < chunksCount) {
|
||||||
|
if (chunks[videoChunkIndex].info[0] != 0xFFFFFFFF || chunks[videoChunkIndex].info[1] != 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (videoChunkIndex >= chunksCount)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const Chunk &chunk = chunks[videoChunkIndex];
|
||||||
|
|
||||||
|
{
|
||||||
|
OS_LOCK(Sound::lock);
|
||||||
|
stream->setPos(chunk.offset);
|
||||||
|
videoChunkData.resize(chunk.size);
|
||||||
|
stream->raw(videoChunkData.items, videoChunkData.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: decode
|
||||||
|
Stream data(NULL, videoChunkData.items + videoChunkPos, videoChunkData.length - videoChunkPos);
|
||||||
|
union FrameHeader {
|
||||||
|
struct { uint32 flags:8, size:24; };
|
||||||
|
uint32 value;
|
||||||
|
} hdr;
|
||||||
|
|
||||||
|
hdr.value = data.readBE32();
|
||||||
|
ASSERT(hdr.size <= videoChunkData.length - videoChunkPos);
|
||||||
|
videoChunkPos += hdr.size;
|
||||||
|
*/
|
||||||
|
for (int y = 0; y < height; y++)
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
Color32 c;
|
||||||
|
c.r = c.g = c.b = x ^ y;
|
||||||
|
c.a = 255;
|
||||||
|
pixels[y * width + x] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int decode(Sound::Frame *frames, int count) {
|
||||||
|
if (audioChunkIndex >= chunksCount) {
|
||||||
|
memset(frames, 0, count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get next audio chunk
|
||||||
|
if (audioChunkPos >= audioChunkFrames.length) {
|
||||||
|
audioChunkPos = 0;
|
||||||
|
|
||||||
|
while (++audioChunkIndex < chunksCount) {
|
||||||
|
if (chunks[audioChunkIndex].info[0] == 0xFFFFFFFF)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audioChunkIndex >= chunksCount) {
|
||||||
|
memset(frames, 0, count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Chunk &chunk = chunks[audioChunkIndex];
|
||||||
|
|
||||||
|
audioChunkFrames.resize(chunk.size / sizeof(Sound::Frame));
|
||||||
|
|
||||||
|
stream->setPos(chunk.offset);
|
||||||
|
// read LEFT channel samples
|
||||||
|
for (int i = 0; i < audioChunkFrames.length; i++)
|
||||||
|
audioChunkFrames[i].L = stream->readBE16();
|
||||||
|
// read RIGHT channel samples
|
||||||
|
for (int i = 0; i < audioChunkFrames.length; i++)
|
||||||
|
audioChunkFrames[i].R = stream->readBE16();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i += 2) {
|
||||||
|
frames[i + 0] = audioChunkFrames[audioChunkPos];
|
||||||
|
frames[i + 1] = audioChunkFrames[audioChunkPos++];
|
||||||
|
|
||||||
|
if (audioChunkPos >= audioChunkFrames.length)
|
||||||
|
return i + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Decoder *decoder;
|
Decoder *decoder;
|
||||||
Texture *frameTex[2];
|
Texture *frameTex[2];
|
||||||
Color32 *frameData;
|
Color32 *frameData;
|
||||||
@@ -1144,11 +1294,15 @@ struct Video {
|
|||||||
|
|
||||||
if (!stream) return;
|
if (!stream) return;
|
||||||
|
|
||||||
uint32 magic;
|
uint32 magic = stream->readLE32();
|
||||||
stream->read(magic);
|
|
||||||
stream->seek(-4);
|
stream->seek(-4);
|
||||||
|
|
||||||
if (magic == 0x6F4D5241)
|
float pitch = 1.0f;
|
||||||
|
|
||||||
|
if (magic == FOURCC("FILM")) {
|
||||||
|
decoder = new Cinepak(stream);
|
||||||
|
pitch = decoder->freq / 22050.0f; // 22254 / 22050 = 1.00925
|
||||||
|
} else if (magic == FOURCC("ARMo"))
|
||||||
decoder = new Escape(stream);
|
decoder = new Escape(stream);
|
||||||
else
|
else
|
||||||
decoder = new STR(stream);
|
decoder = new STR(stream);
|
||||||
@@ -1160,6 +1314,7 @@ struct Video {
|
|||||||
frameTex[i] = new Texture(decoder->width, decoder->height, FMT_RGBA, 0, frameData);
|
frameTex[i] = new Texture(decoder->width, decoder->height, FMT_RGBA, 0, frameData);
|
||||||
|
|
||||||
sample = Sound::play(decoder);
|
sample = Sound::play(decoder);
|
||||||
|
sample->pitch = pitch;
|
||||||
|
|
||||||
step = 1.0f / decoder->fps;
|
step = 1.0f / decoder->fps;
|
||||||
stepTimer = step;
|
stepTimer = step;
|
||||||
|
Reference in New Issue
Block a user