Skip to content

Commit

Permalink
Parse the title graphics 🎞️.
Browse files Browse the repository at this point in the history
  • Loading branch information
gmarty committed May 19, 2024
1 parent 8358b4a commit a4c08dd
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 19 deletions.
2 changes: 1 addition & 1 deletion src/components/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
Expand Down
4 changes: 2 additions & 2 deletions src/components/RoomGfxList.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import ColumnListHeader from './ColumnListHeader';
import ColumnListItem from './ColumnListItem';

const RoomGfxList = ({ roomgfx, currentId }) => {
const RoomGfxList = ({ gfx, currentId }) => {
return (
<>
<ColumnListHeader>Room Gfx</ColumnListHeader>
{roomgfx.map(({ metadata }) => {
{gfx.map(({ metadata }) => {
const selected = metadata.id === currentId;
const path = `/roomgfx/${metadata.id}`;
const label = `Tileset ${metadata.id}`;
Expand Down
25 changes: 25 additions & 0 deletions src/components/TitleGfxList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import ColumnListHeader from './ColumnListHeader';
import ColumnListItem from './ColumnListItem';

const TitleGfxList = ({ gfx, currentId }) => {
return (
<>
<ColumnListHeader>Title Gfx</ColumnListHeader>
{gfx.map(({ metadata }) => {
const selected = metadata.id === currentId;
const path = `/titlegfx/${metadata.id}`;
const label = `Title ${metadata.id}`;

return (
<ColumnListItem
key={metadata.id}
path={selected ? null : path}>
{label}
</ColumnListItem>
);
})}
</>
);
};

export default TitleGfxList;
Original file line number Diff line number Diff line change
@@ -1,48 +1,56 @@
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;
}

return (
<>
<PrimaryColumn>
<RoomGfxList
roomgfx={roomgfx}
currentId={currentGfcId}
gfx={roomgfx}
currentId={isRoomGfx ? currentGfcId : null}
/>
<TitleGfxList
gfx={titlegfx}
currentId={isRoomGfx ? null : currentGfcId}
/>
</PrimaryColumn>
<Main>
<MainHeader
title={
currentGfcId === null
? 'Room graphics'
: `Room graphics tileset ${currentGfcId}`
? 'Graphics'
: isRoomGfx
? `Room graphics tileset ${currentGfcId}`
: `Title graphics tileset ${currentGfcId}`
}>
{currentGfcId !== null && (
<ResourceMetadata metadata={roomgfc.metadata} />
<ResourceMetadata metadata={gfc.metadata} />
)}
</MainHeader>
<GfxCanvasContainer
gfx={roomgfc.gfx}
gfx={gfc.gfx}
zoom={3}
/>
</Main>
</>
);
};

export default RoomGfxContainer;
export default GfxContainer;
34 changes: 31 additions & 3 deletions src/containers/ResourceExplorer.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -35,10 +35,38 @@ const ResourceExplorer = ({ rom, res, resources }) => {
</Route>
<Route
path="/roomgfx"
element={<RoomGfxContainer roomgfx={resources.roomgfx} />}>
element={
<GfxContainer
roomgfx={resources.roomgfx}
titlegfx={resources.titles}
/>
}>
<Route
path=":gfcId"
element={<RoomGfxContainer roomgfx={resources.roomgfx} />}
element={
<GfxContainer
roomgfx={resources.roomgfx}
titlegfx={resources.titles}
/>
}
/>
</Route>
<Route
path="/titlegfx"
element={
<GfxContainer
roomgfx={resources.roomgfx}
titlegfx={resources.titles}
/>
}>
<Route
path=":gfcId"
element={
<GfxContainer
roomgfx={resources.roomgfx}
titlegfx={resources.titles}
/>
}
/>
</Route>
<Route
Expand Down
16 changes: 14 additions & 2 deletions src/lib/parser/parseRom.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import parseRoomGfx from './parseRoomGfx.js';
import parseGlobdata from './parseGlobdata.js';
import parsePreps from './parsePreps.js';
import parseScript from './parseScript.js';
import parseTitles from './parseTitles.js';

const parseRom = (arrayBuffer, res) => {
const rooms = [];
const roomgfx = [];
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];
Expand Down Expand Up @@ -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,
};
};

Expand Down
57 changes: 57 additions & 0 deletions src/lib/parser/parseTitles.js
Original file line number Diff line number Diff line change
@@ -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;
8 changes: 8 additions & 0 deletions src/lib/resources.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -426,6 +429,7 @@ const fra = {
sprdata: [[0x2ca28, 0x2be0], [0x07e48, 0x008a]],
charset: [[0x3f739, 0x009a]],
preplist: [[0x3fbaf, 0x0010]],
titleoffs: [[0x02701, 0x0000], [0x0320f, 0x0000]],
characters: {
'[': 'é', '<': 'à', '\\': 'è', '>': 'ç', ']': 'ê', '|': 'ô',
'{': 'î', '=': 'â', '}': 'ù', '_': 'û',
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -643,6 +648,7 @@ const esp = {
sprdata: [[0x2c401, 0x2be0], [0x0fe67, 0x008a]],
charset: [[0x3f739, 0x0099]],
preplist: [[0x3fbae, 0x000f]],
titleoffs: [[0x02701, 0x0000], [0x0320f, 0x0000]],
characters: {
'[': 'á', '<': 'é', '|': 'í', '>': 'ó', ']': 'ú',
'{': '¿', '}': '¡', '=': 'ñ', '_': 'ü',
Expand Down Expand Up @@ -751,6 +757,7 @@ const ita = {
sprdata: [[0x2c8c0, 0x2be0], [0x0fe61, 0x008a]],
charset: [[0x3f739, 0x0095]],
preplist: [[0x3fbaa, 0x0010]],
titleoffs: [[0x02701, 0x0000], [0x0320f, 0x0000]],
characters: {
'<': 'à', '\\': 'è', '>': 'ì', '|': 'ò', '}': 'ù',
},
Expand Down Expand Up @@ -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',
Expand Down

0 comments on commit a4c08dd

Please sign in to comment.