Vendor grrr emote locally and use PNG in README
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
# useless-umd-player
|
# useless-umd-player
|
||||||
|
|
||||||
|
[grrr](assets/grrr.png)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
a standalone player for PSP UMD Video ISO images: open a disc, render its real
|
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
|
menu, and play the movie (H.264 video + ATRAC3+ audio) with mouse and
|
||||||
keyboard/media-key controls.
|
keyboard/media-key controls.
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,16 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
package dev.quoije.umd.rco;
|
||||||
|
|
||||||
|
/** The rendering surface backing an RCO menu. Implemented by the UI layer. */
|
||||||
|
public interface Display {
|
||||||
|
|
||||||
|
void setFocus(IDisplay display);
|
||||||
|
|
||||||
|
void add(IDisplay display);
|
||||||
|
|
||||||
|
void remove(IDisplay display);
|
||||||
|
|
||||||
|
void repaint();
|
||||||
|
|
||||||
|
void changeResource();
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
package dev.quoije.umd.rco;
|
||||||
|
|
||||||
|
/** A renderable RCO object (plane, button, text, ...). */
|
||||||
|
public interface IDisplay {
|
||||||
|
|
||||||
|
Object getImage();
|
||||||
|
|
||||||
|
Object getAnimImage();
|
||||||
|
|
||||||
|
int getX();
|
||||||
|
|
||||||
|
int getY();
|
||||||
|
|
||||||
|
int getWidth();
|
||||||
|
|
||||||
|
int getHeight();
|
||||||
|
|
||||||
|
float getAlpha();
|
||||||
|
|
||||||
|
void setFocus();
|
||||||
|
|
||||||
|
void focusOut();
|
||||||
|
|
||||||
|
void onUp();
|
||||||
|
|
||||||
|
void onDown();
|
||||||
|
|
||||||
|
void onLeft();
|
||||||
|
|
||||||
|
void onRight();
|
||||||
|
|
||||||
|
void onPush();
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
package dev.quoije.umd.rco;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/** Orders the typed fields of an RCO object record for serialization. */
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
public @interface ObjectField {
|
||||||
|
int order();
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
package dev.quoije.umd.rco;
|
||||||
|
|
||||||
|
import dev.quoije.umd.rco.object.BaseObject;
|
||||||
|
import dev.quoije.umd.rco.object.ImageObject;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutable read cursor and shared reference tables used when deserializing
|
||||||
|
* RCO object and animation records.
|
||||||
|
*/
|
||||||
|
public final class RcoContext {
|
||||||
|
|
||||||
|
public byte[] buffer;
|
||||||
|
public int offset;
|
||||||
|
public Map<Integer, String> events;
|
||||||
|
public Map<Integer, ImageObject> images;
|
||||||
|
public Map<Integer, BaseObject> objects;
|
||||||
|
|
||||||
|
public RcoContext(byte[] buffer, int offset, Map<Integer, String> events,
|
||||||
|
Map<Integer, ImageObject> images, Map<Integer, BaseObject> objects) {
|
||||||
|
this.buffer = buffer;
|
||||||
|
this.offset = offset;
|
||||||
|
this.events = events;
|
||||||
|
this.images = images;
|
||||||
|
this.objects = objects;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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]";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user