Enhance sprite-picker
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="https://alttpr.com/css/app.css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
|
||||
12
package-lock.json
generated
12
package-lock.json
generated
@@ -18,7 +18,8 @@
|
||||
"localforage": "^1.10.0",
|
||||
"mustache": "^4.2.0",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.0"
|
||||
"vue-router": "^4.5.0",
|
||||
"vue-select": "^4.0.0-beta.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@modyfi/vite-plugin-yaml": "^1.1.1",
|
||||
@@ -3143,6 +3144,15 @@
|
||||
"vue": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-select": {
|
||||
"version": "4.0.0-beta.6",
|
||||
"resolved": "https://registry.npmjs.org/vue-select/-/vue-select-4.0.0-beta.6.tgz",
|
||||
"integrity": "sha512-K+zrNBSpwMPhAxYLTCl56gaMrWZGgayoWCLqe5rWwkB8aUbAUh7u6sXjIR7v4ckp2WKC7zEEUY27g6h1MRsIHw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"vue": "3.x"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
"localforage": "^1.10.0",
|
||||
"mustache": "^4.2.0",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.0"
|
||||
"vue-router": "^4.5.0",
|
||||
"vue-select": "^4.0.0-beta.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@modyfi/vite-plugin-yaml": "^1.1.1",
|
||||
|
||||
@@ -12,8 +12,8 @@ export default class ZSPR {
|
||||
}
|
||||
|
||||
_parse() {
|
||||
this.gfxOffset = (this.patch[12] << 24) | (this.patch[11] << 16) | (this.patch[10] << 8) | this.patch[9];
|
||||
this.palOffset = (this.patch[18] << 24) | (this.patch[17] << 16) | (this.patch[16] << 8) | this.patch[15];
|
||||
this.gfxOffset = ((this.patch[12] << 24) | (this.patch[11] << 16) | (this.patch[10] << 8) | this.patch[9]) >>> 0;
|
||||
this.palOffset = ((this.patch[18] << 24) | (this.patch[17] << 16) | (this.patch[16] << 8) | this.patch[15]) >>> 0;
|
||||
const metadataOffset = 0x1D;
|
||||
const dec8 = new TextDecoder("utf-8");
|
||||
const dec16 = new TextDecoder("utf-16");
|
||||
|
||||
@@ -26,3 +26,13 @@
|
||||
--bs-btn-color: #880;
|
||||
--bs-btn-active-color: #550;
|
||||
}
|
||||
|
||||
.sprite-preview-icon {
|
||||
display: inline;
|
||||
float: left;
|
||||
padding-right: 0.7em;
|
||||
}
|
||||
|
||||
.sprite-preview-name {
|
||||
padding-left: 0.7em;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ export default defineComponent({
|
||||
rom_checksum: "3322EFFC",
|
||||
baserom: null,
|
||||
baserom_error: null,
|
||||
sprite: null,
|
||||
patch: null,
|
||||
error: null,
|
||||
settings: null,
|
||||
@@ -54,7 +53,6 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
await this.fetchSeed();
|
||||
|
||||
},
|
||||
computed: {
|
||||
permalink() {
|
||||
@@ -121,15 +119,10 @@ export default defineComponent({
|
||||
}.bind(this);
|
||||
reader.readAsArrayBuffer(file);
|
||||
},
|
||||
spriteUpdate(sprite) {
|
||||
this.sprite = sprite;
|
||||
},
|
||||
async patchRom() {
|
||||
var rom = bps.apply(this.patch, this.baserom);
|
||||
|
||||
if (this.sprite) {
|
||||
this.sprite.apply(rom);
|
||||
}
|
||||
await this.$refs.spritepicker.patch(rom);
|
||||
|
||||
this.$refs.heartbeep.patch(rom);
|
||||
this.$refs.heartcolor.patch(rom);
|
||||
@@ -187,7 +180,7 @@ export default defineComponent({
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<div class="mb-2">
|
||||
<SpritePicker @spriteUpdate="spriteUpdate" />
|
||||
<SpritePicker ref="spritepicker" />
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
|
||||
@@ -3,59 +3,160 @@ import { defineComponent } from 'vue';
|
||||
|
||||
import ZSPR from "@/ZSPR.js";
|
||||
import localforage from "localforage";
|
||||
import officialSprites from "@/data/sprites.json";
|
||||
import axios from "axios";
|
||||
|
||||
import vSelect from "vue-select";
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
vSelect,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
sprite: null,
|
||||
uploadedZspr: null,
|
||||
sprite_error: null,
|
||||
spriteType: null,
|
||||
officialSprite: null,
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
const spriteType = await localforage.getItem("selected_sprite_type") ?? "default";
|
||||
this.officialSprite = await localforage.getItem("selected_official_sprite");
|
||||
const uploaded = await localforage.getItem("uploaded_sprite");
|
||||
if (uploaded) {
|
||||
const dataTransfer = new DataTransfer();
|
||||
dataTransfer.items.add(uploaded);
|
||||
document.getElementById("sprite-input").files = dataTransfer.files;
|
||||
await this.uploadSprite(uploaded, false);
|
||||
}
|
||||
this.spriteType = spriteType;
|
||||
},
|
||||
watch: {
|
||||
async spriteType(newValue, oldValue) {
|
||||
await localforage.setItem("selected_sprite_type", newValue);
|
||||
},
|
||||
async officialSprite(newValue, oldValue) {
|
||||
if (newValue) {
|
||||
this.spriteType = "official";
|
||||
} else {
|
||||
this.spriteType = "default";
|
||||
}
|
||||
await localforage.setItem("selected_official_sprite", JSON.parse(JSON.stringify(newValue)));
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
spriteList() {
|
||||
return officialSprites;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
uploadSprite(file) {
|
||||
async patch(rom) {
|
||||
if (this.spriteType == "custom" && this.uploadedZspr != null) {
|
||||
this.uploadedZspr.apply(rom);
|
||||
} else if (this.spriteType == "official" && this.officialSprite
|
||||
&& this.officialSprite.file) {
|
||||
await axios.get(this.officialSprite.file, { responseType: "arraybuffer" })
|
||||
.then(response => {
|
||||
const buffer = new Uint8Array(response.data);
|
||||
const zspr = new ZSPR(buffer);
|
||||
|
||||
if (!zspr.valid) {
|
||||
throw "Downloaded sprite invalid";
|
||||
return;
|
||||
}
|
||||
|
||||
zspr.apply(rom);
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
},
|
||||
uploadSprite(file, updateType) {
|
||||
if (!file) {
|
||||
this.sprite_error = null;
|
||||
this.sprite = null;
|
||||
this.uploadedZspr = null;
|
||||
if (updateType) {
|
||||
this.spriteType = "default";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function() {
|
||||
reader.onload = async function() {
|
||||
const buffer = new Uint8Array(reader.result);
|
||||
const zspr = new ZSPR(buffer);
|
||||
|
||||
if (!zspr.valid) {
|
||||
this.sprite_error = "Invalid sprite file";
|
||||
this.sprite = null;
|
||||
this.uploadedZspr = null;
|
||||
if (updateType) {
|
||||
this.spriteType = "default";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.sprite_error = null;
|
||||
this.sprite = zspr;
|
||||
localforage.setItem("sprite", file);
|
||||
this.$emit("spriteUpdate", this.sprite);
|
||||
this.uploadedZspr = zspr;
|
||||
if (updateType) {
|
||||
this.spriteType = "custom";
|
||||
}
|
||||
await localforage.setItem("uploaded_sprite", file);
|
||||
}.bind(this);
|
||||
reader.readAsArrayBuffer(file);
|
||||
},
|
||||
}
|
||||
getSpriteClass(name) {
|
||||
return "icon-custom-" + name.replace(/\W/g, "");
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<label for="sprite-input" class="form-label">
|
||||
Custom Sprite:
|
||||
<template v-if="sprite">
|
||||
{{ sprite.spriteName }} by {{ sprite.spriteAuthor }}
|
||||
</template>
|
||||
</label>
|
||||
<input id="sprite-input" class="form-control" type="file" accept=".zspr" @change="uploadSprite($event.target.files[0])" />
|
||||
<div class="input-group mt-2">
|
||||
<div class="input-group-text">
|
||||
<input name="spriteType" v-model="spriteType" value="default" class="mt-0" type="radio">
|
||||
</div>
|
||||
<label class="input-group-text">
|
||||
Default Link Sprite
|
||||
</label>
|
||||
</div>
|
||||
<div class="input-group mt-2">
|
||||
<div class="input-group-text">
|
||||
<input name="spriteType" v-model="spriteType" value="official" class="mt-0" type="radio">
|
||||
</div>
|
||||
<label class="input-group-text" for="spriteSelector">
|
||||
Sprite:
|
||||
</label>
|
||||
<vSelect label="name" :options="spriteList" class="form-control"
|
||||
id="spriteSelector" v-model="officialSprite">
|
||||
<template #option="option">
|
||||
<div class="icon-custom sprite-preview-icon" :class="getSpriteClass(option.name)"></div>
|
||||
<span class="sprite-preview-name">{{ option.name }}</span>
|
||||
</template>
|
||||
<template #selected-option="option">
|
||||
<div class="icon-custom sprite-preview-icon" :class="getSpriteClass(option.name)"></div>
|
||||
<span class="sprite-preview-name">{{ option.name }}</span>
|
||||
</template>
|
||||
</vSelect>
|
||||
</div>
|
||||
<div class="input-group mt-2">
|
||||
<div class="input-group-text">
|
||||
<input name="spriteType" v-model="spriteType" value="custom" class="mt-0" type="radio">
|
||||
</div>
|
||||
<input id="sprite-input" class="form-control" type="file" accept=".zspr" @change="uploadSprite($event.target.files[0], true)" />
|
||||
</div>
|
||||
<div v-if="sprite_error" class="invalid">
|
||||
{{ sprite_error }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
#spriteSelector {
|
||||
padding: 0;
|
||||
--vs-border-style: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
7376
src/data/sprites.json
Normal file
7376
src/data/sprites.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@ import router from "./router";
|
||||
|
||||
import "bootstrap/dist/css/bootstrap.min.css";
|
||||
import "bootstrap-icons/font/bootstrap-icons.css";
|
||||
import "vue-select/dist/vue-select.css";
|
||||
import "bootstrap";
|
||||
|
||||
import "./assets/main.css";
|
||||
|
||||
Reference in New Issue
Block a user