Skip to content

Commit

Permalink
feat: added material table
Browse files Browse the repository at this point in the history
  • Loading branch information
jvenin committed Mar 3, 2024
1 parent a3da88f commit fa54f7b
Show file tree
Hide file tree
Showing 8 changed files with 522 additions and 2 deletions.
6 changes: 6 additions & 0 deletions lib/classes/gsf/header2/header2.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:typed_data';

import 'package:paraworld_gsf_viewer/classes/gsf/header2/materials_table.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/model_settings.dart';
import 'package:paraworld_gsf_viewer/classes/gsf_data.dart';

Expand All @@ -12,6 +13,7 @@ class Header2 extends GsfPart {
late final Standard4BytesData<int> modelsSettingCount;
late final Standard4BytesData<int> animSettingsOffset;
late final Standard4BytesData<int> animSettingsCount;
late final MaterialsTable materialsTable;

late final List<ModelSettings> modelSettings;
// todo: material Header
Expand All @@ -35,6 +37,10 @@ class Header2 extends GsfPart {
position: modelsSettingCount.relativeEnd, bytes: bytes, offset: offset);
animSettingsCount = Standard4BytesData(
position: animSettingsOffset.relativeEnd, bytes: bytes, offset: offset);
materialsTable = MaterialsTable.fromBytes(
bytes,
animSettingsCount.offsettedLength,
);

modelSettings = [];
for (var i = 0; i < modelsSettingCount.value; i++) {
Expand Down
165 changes: 165 additions & 0 deletions lib/classes/gsf/header2/material.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import 'dart:typed_data';

import 'package:paraworld_gsf_viewer/classes/gsf_data.dart';

class MaterialData extends GsfPart {
late final Standard4BytesData<UnknowData> bitsetAttribute1;
late final Standard4BytesData<UnknowData> bitsetAttribute2;
late final Standard4BytesData<int> textureNameOffset;
late final Standard4BytesData<int> nmNameOffset;
late final Standard4BytesData<int> envNameOffset;
late final Standard4BytesData<Uint8List> zeroPadding;

NameStruct? textureName;
NameStruct? nmName;
NameStruct? envName;

@override
String get label {
if (textureName == null && nmName == null && envName == null) {
return "empty material";
}
String label = "";
if (textureName != null) {
label += "texture $textureName\n";
}
if (nmName != null) {
label += "nm $nmName\n";
}
if (envName != null) {
label += "env $envName";
}
return label;
}

MaterialData.fromBytes(Uint8List bytes, int offset) : super(offset: offset) {
bitsetAttribute1 = Standard4BytesData(
position: 0,
bytes: bytes,
offset: offset,
);

bitsetAttribute2 = Standard4BytesData(
position: bitsetAttribute1.relativeEnd,
bytes: bytes,
offset: offset,
);

textureNameOffset = Standard4BytesData(
position: bitsetAttribute2.relativeEnd,
bytes: bytes,
offset: offset,
);

nmNameOffset = Standard4BytesData(
position: textureNameOffset.relativeEnd,
bytes: bytes,
offset: offset,
);

envNameOffset = Standard4BytesData(
position: nmNameOffset.relativeEnd,
bytes: bytes,
offset: offset,
);

zeroPadding = Standard4BytesData(
position: envNameOffset.relativeEnd,
bytes: bytes,
offset: offset,
);

if (textureNameOffset.value & 0x80000000 == 0) {
textureName = NameStruct.fromBytes(
bytes,
textureNameOffset.offsettedPos + textureNameOffset.value,
NameStructType.texture,
);
}

if (nmNameOffset.value & 0x80000000 == 0) {
nmName = NameStruct.fromBytes(
bytes,
nmNameOffset.offsettedPos + nmNameOffset.value,
NameStructType.nm,
);
}

if (envNameOffset.value & 0x80000000 == 0) {
envName = NameStruct.fromBytes(
bytes,
envNameOffset.offsettedPos + envNameOffset.value,
NameStructType.env,
);
}
}

@override
int getEndOffset() {
return zeroPadding.offsettedLength;
}
}

enum NameStructType {
texture,
nm,
env,
}

class NameStruct extends GsfPart {
final NameStructType type;
late final Standard4BytesData<int> stringsCount;
late final Standard4BytesData<int> maxCharactersCount;
late final Standard4BytesData<int> charactersCount;
late final GsfData<StringNoZero> trueName;
late final GsfData<Uint8List> padding;

@override
String get label => "${type.name} ${trueName.value}";

@override
String toString() => trueName.value.value;

NameStruct.fromBytes(
Uint8List bytes,
int offset,
this.type,
) : super(offset: offset) {
stringsCount = Standard4BytesData(
position: 0,
bytes: bytes,
offset: offset,
);

maxCharactersCount = Standard4BytesData(
position: stringsCount.relativeEnd,
bytes: bytes,
offset: offset,
);

charactersCount = Standard4BytesData(
position: maxCharactersCount.relativeEnd,
bytes: bytes,
offset: offset,
);

trueName = GsfData.fromPosition(
relativePos: charactersCount.relativeEnd,
length: charactersCount.value,
bytes: bytes,
offset: offset,
);

padding = GsfData.fromPosition(
relativePos: trueName.relativeEnd,
length: maxCharactersCount.value - charactersCount.value,
bytes: bytes,
offset: offset,
);
}

@override
int getEndOffset() {
return padding.offsettedLength;
}
}
57 changes: 57 additions & 0 deletions lib/classes/gsf/header2/materials_table.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import 'dart:typed_data';

import 'package:paraworld_gsf_viewer/classes/gsf/header2/material.dart';
import 'package:paraworld_gsf_viewer/classes/gsf_data.dart';

class MaterialsTable extends GsfPart {
late final Standard4BytesData<int> materialCount;
late final Standard4BytesData<int> materialOffset;
late final Standard4BytesData<int> maxEntriesCount;
late final List<MaterialData> materials;

@override
String get label => "Materials Table with ${maxEntriesCount.value} materials";

MaterialsTable.fromBytes(Uint8List bytes, int offset)
: super(offset: offset) {
materialCount = Standard4BytesData(
position: 0,
bytes: bytes,
offset: offset,
);

materialOffset = Standard4BytesData(
position: materialCount.relativeEnd,
bytes: bytes,
offset: offset,
);

maxEntriesCount = Standard4BytesData(
position: materialOffset.relativeEnd,
bytes: bytes,
offset: offset,
);

materials = [];
for (var i = 0; i < maxEntriesCount.value; i++) {
materials.add(
MaterialData.fromBytes(
bytes,
materials.isEmpty
? materialOffset.offsettedPos + materialOffset.value
: materials.last.getEndOffset(),
),
);
}
}

@override
int getEndOffset() {
return maxEntriesCount.offsettedLength;
}

@override
String toString() {
return 'MaterialsHeader: $materialCount, $materialOffset';
}
}
60 changes: 58 additions & 2 deletions lib/widgets/header2/display.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/chunks/chunk.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/chunks/mesh.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/chunks/mesh_skinned.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/material.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/materials_table.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/model_settings.dart';
import 'package:paraworld_gsf_viewer/providers/gsf.dart';
import 'package:paraworld_gsf_viewer/widgets/header2/providers.dart';
import 'package:paraworld_gsf_viewer/widgets/header2/state.dart';
import 'package:paraworld_gsf_viewer/widgets/header2/widgets/chunks/mesh.dart';
import 'package:paraworld_gsf_viewer/widgets/header2/widgets/chunks/mesh_skinned.dart';
import 'package:paraworld_gsf_viewer/widgets/header2/widgets/chunks/submesh.dart';
import 'package:paraworld_gsf_viewer/widgets/header2/widgets/material.dart';
import 'package:paraworld_gsf_viewer/widgets/header2/widgets/model_settings.dart';
import 'package:paraworld_gsf_viewer/widgets/utils/data_display.dart';
import 'package:paraworld_gsf_viewer/widgets/utils/label.dart';
Expand Down Expand Up @@ -47,6 +50,7 @@ class _Data extends ConsumerWidget {
final List<Widget> variablePart = state.map(
empty: (_) => [],
withModelSettings: (data) => withModelSettings(data),
withMaterial: (data) => withMaterial(data),
);
return DisplayWrapper(
sideArea: variablePart,
Expand All @@ -73,18 +77,70 @@ class _Data extends ConsumerWidget {
label: 'Anim settings offset', data: header2.animSettingsOffset),
GsfDataTile(
label: 'Anim settings count', data: header2.animSettingsCount),
const Label.large(
"Material table",
fontWeight: FontWeight.bold,
),
_MaterialsTable(materialsTable: header2.materialsTable),
]),
);
}
}

class _MaterialsTable extends ConsumerWidget {
const _MaterialsTable({
super.key,
required this.materialsTable,
});

final MaterialsTable materialsTable;

@override
Widget build(BuildContext context, ref) {
final selected = ref.watch(header2StateNotifierProvider).maybeMap(
withMaterial: (data) => data.material,
orElse: () => null,
);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GsfDataTile(
label: 'Materials count', data: materialsTable.materialCount),
GsfDataTile(
label: 'Materials offset', data: materialsTable.materialOffset),
GsfDataTile(
label: 'Materials count', data: materialsTable.maxEntriesCount),
PartSelector(
value: selected,
label: "materials",
parts: materialsTable.materials,
onSelected: (material) {
ref
.read(header2StateNotifierProvider.notifier)
.setMaterial(material as MaterialData);
})
],
);
}
}

List<Widget> withModelSettings(Header2StateWithModelSettings state) {
return [
ModelSettingsDisplay(modelSettings: state.modelSettings),
if (state.objectName != null)
ObjectNameDisplay(objectName: state.objectName!),
if (state.chunk != null) getChunkWidgetByType(state.chunk!),
if (state.submesh != null) SubmeshDisplay(submesh: state.submesh!),
if (state.chunk != null) ...[
getChunkWidgetByType(state.chunk!),
state.submesh != null
? SubmeshDisplay(submesh: state.submesh!)
: const Flexible(child: SizedBox.shrink()),
]
];
}

List<Widget> withMaterial(Header2StateWithMaterial state) {
return [
MaterialDisplay(material: state.material),
];
}

Expand Down
8 changes: 8 additions & 0 deletions lib/widgets/header2/notifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/gsf.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/chunks/chunk.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/chunks/submesh.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/material.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/model_settings.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/object_name.dart';
import 'package:paraworld_gsf_viewer/providers/gsf.dart';
Expand Down Expand Up @@ -54,4 +55,11 @@ class Header2StateNotifier extends Notifier<Header2State> {
orElse: () => state,
);
}

void setMaterial(MaterialData material) {
state = Header2State.withMaterial(
header2: gsfFile!.header2,
material: material,
);
}
}
5 changes: 5 additions & 0 deletions lib/widgets/header2/state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/chunks/chunk.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/chunks/submesh.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/header2.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/material.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/model_settings.dart';
import 'package:paraworld_gsf_viewer/classes/gsf/header2/object_name.dart';

Expand All @@ -20,4 +21,8 @@ class Header2State with _$Header2State {
Chunk? chunk,
Submesh? submesh,
}) = Header2StateWithModelSettings;

const factory Header2State.withMaterial(
{required Header2 header2,
required MaterialData material}) = Header2StateWithMaterial;
}
Loading

0 comments on commit fa54f7b

Please sign in to comment.