From a29f27cd1dc88626aa37a88eb9534055fd2b8733 Mon Sep 17 00:00:00 2001 From: Mathieu Moran Date: Tue, 15 Sep 2026 22:49:24 -0400 Subject: [PATCH] Vendor grrr emote locally and use PNG in README --- README.md | 4 + assets/grrr.png | Bin 0 -> 24060 bytes .../main/java/dev/quoije/umd/rco/Display.java | 16 ++ .../java/dev/quoije/umd/rco/IDisplay.java | 34 +++ .../java/dev/quoije/umd/rco/ObjectField.java | 14 ++ .../java/dev/quoije/umd/rco/RcoContext.java | 29 +++ .../dev/quoije/umd/rco/object/BaseObject.java | 209 ++++++++++++++++++ .../quoije/umd/rco/object/ImageObject.java | 26 +++ .../umd/rco/type/BaseReferenceType.java | 73 ++++++ .../dev/quoije/umd/rco/type/BaseType.java | 54 +++++ .../dev/quoije/umd/rco/type/EventType.java | 6 + .../dev/quoije/umd/rco/type/FloatType.java | 31 +++ .../dev/quoije/umd/rco/type/ImageType.java | 6 + .../java/dev/quoije/umd/rco/type/IntType.java | 6 + .../dev/quoije/umd/rco/type/ModelType.java | 6 + .../dev/quoije/umd/rco/type/ObjectType.java | 6 + .../java/dev/quoije/umd/rco/type/RefType.java | 6 + .../dev/quoije/umd/rco/type/TextType.java | 6 + .../dev/quoije/umd/rco/type/UnknownType.java | 6 + 19 files changed, 538 insertions(+) create mode 100644 assets/grrr.png create mode 100644 core/src/main/java/dev/quoije/umd/rco/Display.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/IDisplay.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/ObjectField.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/RcoContext.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/object/BaseObject.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/object/ImageObject.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/type/BaseReferenceType.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/type/BaseType.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/type/EventType.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/type/FloatType.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/type/ImageType.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/type/IntType.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/type/ModelType.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/type/ObjectType.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/type/RefType.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/type/TextType.java create mode 100644 core/src/main/java/dev/quoije/umd/rco/type/UnknownType.java diff --git a/README.md b/README.md index 1270942..5f0f56d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # useless-umd-player +[grrr](assets/grrr.png) + +![AI Generated](https://raw.githubusercontent.com/dotnetdave/ai-usage-badges/refs/heads/main/badges/png/1x/ai-generated.png) + a standalone player for PSP UMD Video ISO images: open a disc, render its real menu, and play the movie (H.264 video + ATRAC3+ audio) with mouse and keyboard/media-key controls. diff --git a/assets/grrr.png b/assets/grrr.png new file mode 100644 index 0000000000000000000000000000000000000000..8e89fdb55028b641f472713250261a894fff1851 GIT binary patch literal 24060 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 events; + public Map images; + public Map objects; + + public RcoContext(byte[] buffer, int offset, Map events, + Map images, Map objects) { + this.buffer = buffer; + this.offset = offset; + this.events = events; + this.images = images; + this.objects = objects; + } +} diff --git a/core/src/main/java/dev/quoije/umd/rco/object/BaseObject.java b/core/src/main/java/dev/quoije/umd/rco/object/BaseObject.java new file mode 100644 index 0000000..522353d --- /dev/null +++ b/core/src/main/java/dev/quoije/umd/rco/object/BaseObject.java @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +package dev.quoije.umd.rco.object; + +import dev.quoije.umd.rco.Display; +import dev.quoije.umd.rco.ObjectField; +import dev.quoije.umd.rco.RcoContext; +import dev.quoije.umd.rco.RcoFile; +import dev.quoije.umd.rco.type.BaseType; +import dev.quoije.umd.rco.type.EventType; +import dev.quoije.umd.rco.vsmx.interpreter.VsmxBaseObject; +import dev.quoije.umd.rco.vsmx.interpreter.VsmxInterpreter; +import dev.quoije.umd.rco.vsmx.interpreter.VsmxNativeObject; +import dev.quoije.umd.rco.vsmx.interpreter.VsmxString; +import dev.quoije.umd.rco.vsmx.objects.BaseNativeObject; +import dev.quoije.umd.rco.vsmx.objects.Controller; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Comparator; + +/** + * Base of RCO object records (pages, planes, buttons, ...). Fields are + * declared as {@link BaseType} subclasses and read/measured via reflection, + * mirroring JPCSP's object model. + */ +public abstract class BaseObject extends BaseNativeObject implements IDisplay { + + protected Display display; + protected Controller controller; + private String name; + private BaseNativeObject parent; + + private Field[] getSortedFields() { + Field[] fields = getClass().getFields(); + Arrays.sort(fields, Comparator.comparingInt(f -> { + ObjectField annotation = f.getAnnotation(ObjectField.class); + return annotation == null ? Integer.MAX_VALUE : annotation.order(); + })); + return fields; + } + + /** Deserializes all typed fields from the record data. */ + public void read(RcoContext context) { + for (Field field : getSortedFields()) { + if (BaseType.class.isAssignableFrom(field.getType())) { + try { + BaseType type = (BaseType) field.get(this); + if (type == null) { + type = (BaseType) field.getType().getDeclaredConstructor().newInstance(); + field.set(this, type); + } + type.read(context); + } catch (ReflectiveOperationException e) { + // Ignore + } + } + } + } + + /** Size in bytes of the serialized typed fields. */ + public int size() { + int size = 0; + for (Field field : getSortedFields()) { + if (BaseType.class.isAssignableFrom(field.getType())) { + try { + BaseType type = (BaseType) field.get(this); + if (type == null) { + type = (BaseType) field.getType().getDeclaredConstructor().newInstance(); + } + size += type.size(); + } catch (ReflectiveOperationException e) { + // Ignore + } + } + } + return size; + } + + /** Resolves reference fields against the RCO tables. */ + public void init(RcoContext context) { + for (Field field : getSortedFields()) { + if (BaseType.class.isAssignableFrom(field.getType())) { + try { + BaseType type = (BaseType) field.get(this); + if (type != null) { + type.init(context); + } + } catch (ReflectiveOperationException e) { + // Ignore + } + } + } + } + + /** Creates the VSMX-side object and registers it under the entry label. */ + public VsmxBaseObject createVsmxObject(VsmxInterpreter interpreter, VsmxBaseObject parent, RcoFile.Entry entry) { + VsmxNativeObject object = new VsmxNativeObject(interpreter, this); + setObject(object); + if (entry.label != null) { + name = entry.label; + object.setPropertyValue("name", new VsmxString(interpreter, entry.label)); + parent.setPropertyValue(entry.label, object); + } + if (entry.parent != null && entry.parent.vsmxObject instanceof VsmxNativeObject parentNative) { + setParent(parentNative.getObject()); + } + return object; + } + + public void setDisplay(Display display) { + this.display = display; + } + + public void setController(Controller controller) { + this.controller = controller; + } + + public BaseNativeObject getParent() { + return parent; + } + + public void setParent(BaseNativeObject parent) { + this.parent = parent; + } + + public String getName() { + return name; + } + + protected void trigger(EventType event) { + if (event.getEvent() != null && controller != null) { + controller.getInterpreter().interpretScript(getObject(), event.getEvent()); + } + } + + protected void onDisplayUpdated() { + if (display != null) { + display.repaint(); + } + } + + @Override + public Object getImage() { + return null; + } + + @Override + public Object getAnimImage() { + return getImage(); + } + + @Override + public int getX() { + return 0; + } + + @Override + public int getY() { + return 0; + } + + @Override + public int getWidth() { + return 0; + } + + @Override + public int getHeight() { + return 0; + } + + @Override + public float getAlpha() { + return 1f; + } + + @Override + public void setFocus() { + } + + @Override + public void focusOut() { + } + + @Override + public void onUp() { + } + + @Override + public void onDown() { + } + + @Override + public void onLeft() { + } + + @Override + public void onRight() { + } + + @Override + public void onPush() { + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[name=" + name + "]"; + } +} diff --git a/core/src/main/java/dev/quoije/umd/rco/object/ImageObject.java b/core/src/main/java/dev/quoije/umd/rco/object/ImageObject.java new file mode 100644 index 0000000..9377a4a --- /dev/null +++ b/core/src/main/java/dev/quoije/umd/rco/object/ImageObject.java @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +package dev.quoije.umd.rco.object; + +/** An image entry from the RCO IMG table (raw bytes until decoded by the UI). */ +public final class ImageObject { + + private final byte[] data; + + public ImageObject(byte[] data) { + this.data = data; + } + + public byte[] getData() { + return data; + } + + /** Returns the decoded image, or null (decoded lazily by the renderer). */ + public Object getImage() { + return null; + } + + @Override + public String toString() { + return "ImageObject[" + (data == null ? 0 : data.length) + " bytes]"; + } +} diff --git a/core/src/main/java/dev/quoije/umd/rco/type/BaseReferenceType.java b/core/src/main/java/dev/quoije/umd/rco/type/BaseReferenceType.java new file mode 100644 index 0000000..017c090 --- /dev/null +++ b/core/src/main/java/dev/quoije/umd/rco/type/BaseReferenceType.java @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +package dev.quoije.umd.rco.type; + +import dev.quoije.umd.rco.RcoContext; +import dev.quoije.umd.rco.object.BaseObject; +import dev.quoije.umd.rco.object.ImageObject; + +/** + * An 8-byte reference field: a 16-bit reference type, a 16-bit unknown + * value, and a 32-bit reference index. + */ +public class BaseReferenceType extends BaseType { + + public static final int REFERENCE_TYPE_NONE = 0xFFFF; + public static final int REFERENCE_TYPE_EVENT = 0x400; + public static final int REFERENCE_TYPE_TEXT = 0x401; + public static final int REFERENCE_TYPE_IMAGE = 0x402; + public static final int REFERENCE_TYPE_MODEL = 0x403; + public static final int REFERENCE_TYPE_FONT = 0x405; + public static final int REFERENCE_TYPE_OBJECT = 0x407; + public static final int REFERENCE_TYPE_ANIM = 0x408; + public static final int REFERENCE_TYPE_POSITION_OBJECT = 0x409; + + public int referenceType; + public int unknownShort; + protected String event; + protected BaseObject object; + protected ImageObject image; + + @Override + public int size() { + return 8; + } + + @Override + public void read(RcoContext context) { + referenceType = read16(context); + unknownShort = read16(context); + super.read(context); + } + + @Override + public void init(RcoContext context) { + switch (referenceType) { + case REFERENCE_TYPE_NONE -> { } + case REFERENCE_TYPE_EVENT -> event = context.events.get(value); + case REFERENCE_TYPE_OBJECT, REFERENCE_TYPE_POSITION_OBJECT, REFERENCE_TYPE_ANIM -> + object = context.objects.get(value); + case REFERENCE_TYPE_IMAGE -> image = context.images.get(value); + default -> { } + } + super.init(context); + } + + public String getEvent() { + return event; + } + + public BaseObject getObject() { + return object; + } + + public ImageObject getImage() { + return image; + } + + @Override + public String toString() { + return "referenceType=0x" + Integer.toHexString(referenceType) + + ", short1=0x" + Integer.toHexString(unknownShort) + + ", value=0x" + Integer.toHexString(value); + } +} diff --git a/core/src/main/java/dev/quoije/umd/rco/type/BaseType.java b/core/src/main/java/dev/quoije/umd/rco/type/BaseType.java new file mode 100644 index 0000000..6522f54 --- /dev/null +++ b/core/src/main/java/dev/quoije/umd/rco/type/BaseType.java @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +package dev.quoije.umd.rco.type; + +import dev.quoije.umd.rco.RcoContext; + +/** Base of the typed fields inside an RCO object record. */ +public class BaseType { + + protected int value; + + public int size() { + return 4; + } + + protected int read8(RcoContext context) { + return context.buffer[context.offset++] & 0xFF; + } + + protected int read16(RcoContext context) { + return read8(context) | (read8(context) << 8); + } + + protected int read32(RcoContext context) { + return read16(context) | (read16(context) << 16); + } + + public void read(RcoContext context) { + value = read32(context); + } + + public void init(RcoContext context) { + } + + public int getIntValue() { + return value; + } + + public void setIntValue(int value) { + this.value = value; + } + + public float getFloatValue() { + return (float) value; + } + + public void setFloatValue(float value) { + this.value = (int) value; + } + + @Override + public String toString() { + return "value=0x" + Integer.toHexString(getIntValue()); + } +} diff --git a/core/src/main/java/dev/quoije/umd/rco/type/EventType.java b/core/src/main/java/dev/quoije/umd/rco/type/EventType.java new file mode 100644 index 0000000..975c5d1 --- /dev/null +++ b/core/src/main/java/dev/quoije/umd/rco/type/EventType.java @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +package dev.quoije.umd.rco.type; + +/** Reference to a script event. */ +public class EventType extends BaseReferenceType { +} diff --git a/core/src/main/java/dev/quoije/umd/rco/type/FloatType.java b/core/src/main/java/dev/quoije/umd/rco/type/FloatType.java new file mode 100644 index 0000000..c4e1a03 --- /dev/null +++ b/core/src/main/java/dev/quoije/umd/rco/type/FloatType.java @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +package dev.quoije.umd.rco.type; + +/** A 32-bit floating-point field stored as IEEE 754 bits. */ +public class FloatType extends BaseType { + + @Override + public float getFloatValue() { + return Float.intBitsToFloat(super.getIntValue()); + } + + @Override + public void setFloatValue(float value) { + super.setIntValue(Float.floatToRawIntBits(value)); + } + + @Override + public int getIntValue() { + return (int) getFloatValue(); + } + + @Override + public void setIntValue(int value) { + setFloatValue((float) value); + } + + @Override + public String toString() { + return "value=" + getFloatValue(); + } +} diff --git a/core/src/main/java/dev/quoije/umd/rco/type/ImageType.java b/core/src/main/java/dev/quoije/umd/rco/type/ImageType.java new file mode 100644 index 0000000..b262dab --- /dev/null +++ b/core/src/main/java/dev/quoije/umd/rco/type/ImageType.java @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +package dev.quoije.umd.rco.type; + +/** Reference to an image entry. */ +public class ImageType extends BaseReferenceType { +} diff --git a/core/src/main/java/dev/quoije/umd/rco/type/IntType.java b/core/src/main/java/dev/quoije/umd/rco/type/IntType.java new file mode 100644 index 0000000..674f8ba --- /dev/null +++ b/core/src/main/java/dev/quoije/umd/rco/type/IntType.java @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +package dev.quoije.umd.rco.type; + +/** A 32-bit integer field. */ +public class IntType extends BaseType { +} diff --git a/core/src/main/java/dev/quoije/umd/rco/type/ModelType.java b/core/src/main/java/dev/quoije/umd/rco/type/ModelType.java new file mode 100644 index 0000000..59ea6b6 --- /dev/null +++ b/core/src/main/java/dev/quoije/umd/rco/type/ModelType.java @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +package dev.quoije.umd.rco.type; + +/** Reference to a model entry. */ +public class ModelType extends BaseReferenceType { +} diff --git a/core/src/main/java/dev/quoije/umd/rco/type/ObjectType.java b/core/src/main/java/dev/quoije/umd/rco/type/ObjectType.java new file mode 100644 index 0000000..e2f3742 --- /dev/null +++ b/core/src/main/java/dev/quoije/umd/rco/type/ObjectType.java @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +package dev.quoije.umd.rco.type; + +/** Reference to an object entry. */ +public class ObjectType extends BaseReferenceType { +} diff --git a/core/src/main/java/dev/quoije/umd/rco/type/RefType.java b/core/src/main/java/dev/quoije/umd/rco/type/RefType.java new file mode 100644 index 0000000..c44b8f5 --- /dev/null +++ b/core/src/main/java/dev/quoije/umd/rco/type/RefType.java @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +package dev.quoije.umd.rco.type; + +/** Reference to an arbitrary RCO entry. */ +public class RefType extends BaseReferenceType { +} diff --git a/core/src/main/java/dev/quoije/umd/rco/type/TextType.java b/core/src/main/java/dev/quoije/umd/rco/type/TextType.java new file mode 100644 index 0000000..d6e782a --- /dev/null +++ b/core/src/main/java/dev/quoije/umd/rco/type/TextType.java @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +package dev.quoije.umd.rco.type; + +/** Reference to a text entry. */ +public class TextType extends BaseReferenceType { +} diff --git a/core/src/main/java/dev/quoije/umd/rco/type/UnknownType.java b/core/src/main/java/dev/quoije/umd/rco/type/UnknownType.java new file mode 100644 index 0000000..ecfe45b --- /dev/null +++ b/core/src/main/java/dev/quoije/umd/rco/type/UnknownType.java @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +package dev.quoije.umd.rco.type; + +/** A 32-bit field of unknown semantics. */ +public class UnknownType extends BaseType { +}