diff --git a/src/components/Header.js b/src/components/Header.js
index 8b27000..d5c05e2 100644
--- a/src/components/Header.js
+++ b/src/components/Header.js
@@ -15,7 +15,7 @@ import meteor from '../assets/meteor.png';
const navigation = [
{ name: 'Rooms', href: '/rooms/1' },
- { name: 'Room Gfx', href: '/roomgfx/0' },
+ { name: 'Gfx', href: '/roomgfx/0' },
{ name: 'Scripts', href: '/scripts/1' },
{ name: 'Prepositions', href: '/preps' },
{ name: 'ROM map', href: '/rom-map' },
diff --git a/src/components/RoomGfxList.js b/src/components/RoomGfxList.js
index 43e9cb3..7883853 100644
--- a/src/components/RoomGfxList.js
+++ b/src/components/RoomGfxList.js
@@ -1,11 +1,11 @@
import ColumnListHeader from './ColumnListHeader';
import ColumnListItem from './ColumnListItem';
-const RoomGfxList = ({ roomgfx, currentId }) => {
+const RoomGfxList = ({ gfx, currentId }) => {
return (
<>
- Room Gfx
- {roomgfx.map(({ metadata }) => {
+ Room gfx
+ {gfx.map(({ metadata }) => {
const selected = metadata.id === currentId;
const path = `/roomgfx/${metadata.id}`;
const label = `Tileset ${metadata.id}`;
diff --git a/src/components/TitleGfxList.js b/src/components/TitleGfxList.js
new file mode 100644
index 0000000..6938aaf
--- /dev/null
+++ b/src/components/TitleGfxList.js
@@ -0,0 +1,25 @@
+import ColumnListHeader from './ColumnListHeader';
+import ColumnListItem from './ColumnListItem';
+
+const TitleGfxList = ({ gfx, currentId }) => {
+ return (
+ <>
+ Title gfx
+ {gfx.map(({ metadata }) => {
+ const selected = metadata.id === currentId;
+ const path = `/titlegfx/${metadata.id}`;
+ const label = `Tileset ${metadata.id}`;
+
+ return (
+
+ {label}
+
+ );
+ })}
+ >
+ );
+};
+
+export default TitleGfxList;
diff --git a/src/containers/RoomGfxContainer.js b/src/containers/GfxContainer.js
similarity index 51%
rename from src/containers/RoomGfxContainer.js
rename to src/containers/GfxContainer.js
index cc99d2e..370fe13 100644
--- a/src/containers/RoomGfxContainer.js
+++ b/src/containers/GfxContainer.js
@@ -1,19 +1,21 @@
-import { useParams } from 'react-router-dom';
+import { useMatch, useParams } from 'react-router-dom';
import PrimaryColumn from '../components/PrimaryColumn';
import RoomGfxList from '../components/RoomGfxList';
+import TitleGfxList from '../components/TitleGfxList';
import Main from '../components/Main';
import MainHeader from '../components/MainHeader';
import ResourceMetadata from '../components/ResourceMetadata';
import GfxCanvasContainer from './GfxCanvasContainer';
-const RoomGfxContainer = ({ roomgfx }) => {
+const GfxContainer = ({ roomgfx, titlegfx }) => {
+ const isRoomGfx = !!useMatch('/roomgfx/:gfcId');
const { gfcId } = useParams();
const currentGfcId =
typeof gfcId === 'undefined' ? null : parseInt(gfcId, 10);
- const roomgfc = roomgfx[currentGfcId];
+ const gfc = isRoomGfx ? roomgfx[currentGfcId] : titlegfx[currentGfcId];
- if (!roomgfc) {
+ if (!gfc) {
return null;
}
@@ -21,23 +23,29 @@ const RoomGfxContainer = ({ roomgfx }) => {
<>
+
{currentGfcId !== null && (
-
+
)}
@@ -45,4 +53,4 @@ const RoomGfxContainer = ({ roomgfx }) => {
);
};
-export default RoomGfxContainer;
+export default GfxContainer;
diff --git a/src/containers/ResourceExplorer.js b/src/containers/ResourceExplorer.js
index ed2178b..da24dc4 100644
--- a/src/containers/ResourceExplorer.js
+++ b/src/containers/ResourceExplorer.js
@@ -1,6 +1,6 @@
import { Routes, Route } from 'react-router-dom';
import RoomsContainer from './RoomsContainer';
-import RoomGfxContainer from './RoomGfxContainer';
+import GfxContainer from './GfxContainer';
import PrepositionsContainer from './PrepositionsContainer';
import RomMapContainer from './RomMapContainer';
import SettingsContainer from './SettingsContainer';
@@ -35,10 +35,38 @@ const ResourceExplorer = ({ rom, res, resources }) => {
}>
+ element={
+
+ }>
}
+ element={
+
+ }
+ />
+
+
+ }>
+
+ }
/>
{
const rooms = [];
@@ -10,7 +11,7 @@ const parseRom = (arrayBuffer, res) => {
const globdata = [];
const scripts = [];
const preps = [];
- let objects = [];
+ const titles = [];
for (let i = 0; i < res?.rooms?.length; i++) {
const [offset, length] = res.rooms[i];
@@ -56,13 +57,24 @@ const parseRom = (arrayBuffer, res) => {
preps.push(item);
}
+ // The title screens are stored outside of SCUMM.
+ for (let i = 0; i < res?.titleoffs?.length; i++) {
+ const [offset, length] = res.titleoffs[i];
+
+ // @todo Figure out the length of the title chunks.
+ const buffer = arrayBuffer.slice(offset); //, offset + length);
+ const item = parseTitles(buffer, i, offset);
+ item.buffer = buffer;
+ titles.push(item);
+ }
+
return {
rooms,
roomgfx,
globdata,
preps,
scripts,
- objects,
+ titles,
};
};
diff --git a/src/lib/parser/parseTitles.js b/src/lib/parser/parseTitles.js
new file mode 100644
index 0000000..93e2747
--- /dev/null
+++ b/src/lib/parser/parseTitles.js
@@ -0,0 +1,57 @@
+import Parser from './parser.js';
+import { hex } from '../utils.js';
+
+const assert = console.assert;
+
+const parseTitles = (arrayBuffer, i = 0, offset = 0) => {
+ const parser = new Parser(arrayBuffer);
+ const metadata = {
+ id: i,
+ offset,
+ size: arrayBuffer.byteLength,
+ // decompressedSize: 0, // Comment out decompressed size until the buffer size is known.
+ };
+
+ const unk1 = parser.getUint16(); // Probably resource length unused in titles.
+ const unk2 = parser.getUint16();
+
+ assert(unk1 === 0, 'Unknown 1 is not 0.');
+ assert(unk2 === 0x0f10, 'Unknown 2 is not 0x0f10.');
+
+ const numberOfTiles = parser.getUint8() + 1;
+
+ console.log('numberOfTiles', numberOfTiles);
+
+ const gfx = [];
+ let n = 0;
+ while (n < numberOfTiles * 16) {
+ const loop = parser.getUint8();
+ if (loop & 0x80) {
+ for (let j = 0; j < (loop & 0x7f); j++) {
+ gfx[n++] = parser.getUint8();
+ }
+ } else {
+ const data = parser.getUint8();
+ for (let j = 0; j < (loop & 0x7f); j++) {
+ gfx[n++] = data;
+ }
+ }
+ }
+
+ assert(
+ numberOfTiles === gfx.length / 8 / 2,
+ 'Number of tiles byte does not match number of tiles decoded.',
+ );
+
+ // metadata.decompressedSize = gfx.length;
+
+ return {
+ metadata,
+ unk1,
+ unk2,
+ numberOfTiles,
+ gfx,
+ };
+};
+
+export default parseTitles;
diff --git a/src/lib/resources.js b/src/lib/resources.js
index 2ee6b53..b190021 100644
--- a/src/lib/resources.js
+++ b/src/lib/resources.js
@@ -102,6 +102,7 @@ const usa = {
sprdata: [[0x2ce11, 0x2be0], [0x07f6b, 0x008a]],
charset: [[0x3f6ee, 0x0090]],
preplist: [[0x3fb5a, 0x000e]],
+ titleoffs: [[0x2701, 0x0000], [0x324d, 0x0000]],
characters: {},
version: 'USA',
lang: 'en-US',
@@ -212,6 +213,7 @@ const eur = {
sprdata: [[0x2ce11, 0x2be0], [0x0be28, 0x008a]],
charset: [[0x3f724, 0x0090]],
preplist: [[0x3fb90, 0x000e]],
+ titleoffs: [[0x2701, 0x0000], [0x324d, 0x0000]],
characters: {},
version: 'Europe',
lang: 'en-GB',
@@ -317,6 +319,7 @@ const swe = {
sprdata: [[0x2c401, 0x2be0], [0x0fe6b, 0x008a]],
charset: [[0x3f739, 0x0094]],
preplist: [[0x3fba9, 0x000e]],
+ titleoffs: [[0x02701, 0x0000], [0x0320f, 0x0000]],
characters: {
'<': 'ä', '[': 'é', '\\': 'å', '>': 'ö',
// The 'ù' sign is in the base tileset but
@@ -426,6 +429,7 @@ const fra = {
sprdata: [[0x2ca28, 0x2be0], [0x07e48, 0x008a]],
charset: [[0x3f739, 0x009a]],
preplist: [[0x3fbaf, 0x0010]],
+ titleoffs: [[0x02701, 0x0000], [0x0320f, 0x0000]],
characters: {
'[': 'é', '<': 'à', '\\': 'è', '>': 'ç', ']': 'ê', '|': 'ô',
'{': 'î', '=': 'â', '}': 'ù', '_': 'û',
@@ -534,6 +538,7 @@ const ger = {
sprdata: [[0x2c8ee, 0x2be0], [0x0fe61, 0x008a]],
charset: [[0x3f739, 0x0096]],
preplist: [[0x3fbab, 0x000e]],
+ titleoffs: [[0x02701, 0x0000], [0x0320f, 0x0000]],
characters: {
'=': 'ß', '\\': 'ä', '{': 'ö', '[': 'ü', '(': '(', ')': ')',
// The 'è' sign is in the base tileset but
@@ -643,6 +648,7 @@ const esp = {
sprdata: [[0x2c401, 0x2be0], [0x0fe67, 0x008a]],
charset: [[0x3f739, 0x0099]],
preplist: [[0x3fbae, 0x000f]],
+ titleoffs: [[0x02701, 0x0000], [0x0320f, 0x0000]],
characters: {
'[': 'á', '<': 'é', '|': 'í', '>': 'ó', ']': 'ú',
'{': '¿', '}': '¡', '=': 'ñ', '_': 'ü',
@@ -751,6 +757,7 @@ const ita = {
sprdata: [[0x2c8c0, 0x2be0], [0x0fe61, 0x008a]],
charset: [[0x3f739, 0x0095]],
preplist: [[0x3fbaa, 0x0010]],
+ titleoffs: [[0x02701, 0x0000], [0x0320f, 0x0000]],
characters: {
'<': 'à', '\\': 'è', '>': 'ì', '|': 'ò', '}': 'ù',
},
@@ -863,6 +870,7 @@ const proto = {
sprdata: [[0x2ce11, 0x2be0], [0x07f6b, 0x008a]],
charset: [[0x3f6ee, 0x0090]],
preplist: [[0x3fb5a, 0x000e]],
+ titleoffs: [[0x2701, 0x0000], [0x325b, 0x0000]],
characters: {},
version: 'prototype',
lang: 'en-US',