use game font for preview
This commit is contained in:
parent
5f81c7b9b1
commit
4589c52349
9 changed files with 2641 additions and 23 deletions
|
@ -11,7 +11,8 @@
|
||||||
<span v-else>{{ getLabel('codeinfo.author') }} {{ translatedCode.author }}</span>
|
<span v-else>{{ getLabel('codeinfo.author') }} {{ translatedCode.author }}</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="description" v-html="translatedCode.description"></p>
|
<p class="description" v-html="translatedCode.description"></p>
|
||||||
<component v-if="configUI" :is="configUI" :version="version"></component>
|
<component v-if="configUI" :is="configUI" :version="version"
|
||||||
|
:codeConfigs="codeConfigs" @config="$emit('config', {[code.id]: $event})" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ export default {
|
||||||
anchor: { type: Boolean },
|
anchor: { type: Boolean },
|
||||||
code: { type: Object },
|
code: { type: Object },
|
||||||
version: { type: String },
|
version: { type: String },
|
||||||
|
codeConfigs: { type: Object },
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
translatedCode: function () {
|
translatedCode: function () {
|
||||||
|
|
|
@ -42,7 +42,8 @@
|
||||||
|
|
||||||
<div v-if="codes && codes.length > 0" class="help">
|
<div v-if="codes && codes.length > 0" class="help">
|
||||||
<h3>{{ getLabel('headers.help') }}</h3>
|
<h3>{{ getLabel('headers.help') }}</h3>
|
||||||
<CodeInfo v-if="!!inspectingCode" :code="inspectingCode" :version="selectedVersion" />
|
<CodeInfo v-if="!!inspectingCode" :code="inspectingCode" :version="selectedVersion"
|
||||||
|
:codeConfigs="codeConfigs" @config="onCodeConfigChanged" />
|
||||||
<div v-else-if="showStageLoaderHelp">
|
<div v-else-if="showStageLoaderHelp">
|
||||||
<h3>{{ getLabel('headers.stageloader') }}</h3>
|
<h3>{{ getLabel('headers.stageloader') }}</h3>
|
||||||
<div>
|
<div>
|
||||||
|
@ -109,6 +110,9 @@ import gameVersions from '../data/gameVersions.json';
|
||||||
// Util
|
// Util
|
||||||
import { translate } from '../i18n/localeHelper';
|
import { translate } from '../i18n/localeHelper';
|
||||||
|
|
||||||
|
// Code Configs
|
||||||
|
import {getConfig as qftGetConfig} from './codes/qft/codegen';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -122,6 +126,12 @@ export default {
|
||||||
stageLoaderCodes: [],
|
stageLoaderCodes: [],
|
||||||
showStageLoaderHelp: false,
|
showStageLoaderHelp: false,
|
||||||
generation: 0,
|
generation: 0,
|
||||||
|
codeConfigs: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.codeConfigs = {
|
||||||
|
qft: qftGetConfig(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -192,6 +202,10 @@ export default {
|
||||||
this.showStageLoaderHelp = false;
|
this.showStageLoaderHelp = false;
|
||||||
this.inspectingCode = code;
|
this.inspectingCode = code;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onCodeConfigChanged(e) {
|
||||||
|
this.codeConfigs = {...this.codeConfigs, ...e};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
66
site/.vuepress/components/Preview.vue
Normal file
66
site/.vuepress/components/Preview.vue
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<template>
|
||||||
|
<div class="preview-root">
|
||||||
|
<div class="preview-ctn">
|
||||||
|
<div :style="qft.bgStyle" />
|
||||||
|
<PreviewString v-if="qft" :x="qft.x" :y="qft.y" :size="qft.fontSize" :color="qft.color" text="0:00:00" />
|
||||||
|
<PreviewString v-if="mdp" :x="mdp.x" :y="mdp.y" :size="mdp.fontSize" :color="mdp.color" :text="mdp.text" />
|
||||||
|
<PreviewString :x="16" :y="320" :size="20" :color="'#fff'" text="Pattern #0 0 0" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
config: {type: Object},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
mdp() {
|
||||||
|
return {
|
||||||
|
x: 16,
|
||||||
|
y: 200,
|
||||||
|
fontSize: 20,
|
||||||
|
color: '#fff',
|
||||||
|
text: 'X Pos -4\nY Pos 27\nZ Pos -1515\nAngle 3117\nH Spd 4.26\nV Spd 4.28',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
qft() {
|
||||||
|
const {config: {qft}} = this;
|
||||||
|
if (qft == null) return;
|
||||||
|
const {x, y, fontSize, fgRGB, fgA, fgRGB2, fgA2, bgRGB, bgA, width} = qft;
|
||||||
|
const i2s = (rgb, a) => '#'+rgb.toString(16).padStart('0', 6)+a.toString(16).padStart('0', 2);
|
||||||
|
const bg = i2s(bgRGB, bgA);
|
||||||
|
const fg1 = i2s(fgRGB, fgA);
|
||||||
|
return {
|
||||||
|
x, y, fontSize,
|
||||||
|
color: fgRGB2==null || fgA2==null ? fg1 : `linear-gradient(180deg, ${fg1}, ${i2s(fgRGB2, fgA2)})`,
|
||||||
|
bgStyle: {
|
||||||
|
left: x+'px',
|
||||||
|
top: (y-fontSize)+'px',
|
||||||
|
width: (width*fontSize/20)+'px',
|
||||||
|
height: fontSize+'px',
|
||||||
|
background: bg,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
div.preview-root {
|
||||||
|
position: relative;
|
||||||
|
width: 600px;
|
||||||
|
height: 448px;
|
||||||
|
background: url(/img/preview/background.png);
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
div.preview-ctn {
|
||||||
|
position: absolute;
|
||||||
|
top: -16px;
|
||||||
|
}
|
||||||
|
div.preview-ctn * {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
</style>
|
97
site/.vuepress/components/PreviewString.vue
Normal file
97
site/.vuepress/components/PreviewString.vue
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<template>
|
||||||
|
<div class="preview-str" :style="styles.root" >
|
||||||
|
<div v-for="style, i in styles.chars" :key="i" class="char-ctn" :style="style.ctn">
|
||||||
|
<div class="char-bg" :style="style.bg" />
|
||||||
|
<div class="char-mask" :style="style.mask" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import charInfo from '../data/font-jp.json';
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
x: {type: Number},
|
||||||
|
y: {type: Number},
|
||||||
|
size: {type: Number},
|
||||||
|
color: {type: String},
|
||||||
|
text: {type: String},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
styles() {
|
||||||
|
const {x: x0, y: y0, size: fontSize, color, text} = this;
|
||||||
|
|
||||||
|
/** @type {{x: number, y: number, u: number, v: number}[]} */
|
||||||
|
const chars = [];
|
||||||
|
let x = 0;
|
||||||
|
let y = 0;
|
||||||
|
let useKerning = false;
|
||||||
|
text.split('').forEach(c => {
|
||||||
|
const {index, kerning, width} = charInfo[c] ?? charInfo[' '];
|
||||||
|
if (c === '\n') {
|
||||||
|
useKerning = false;
|
||||||
|
x = 0;
|
||||||
|
y += 20;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (useKerning) x -= kerning;
|
||||||
|
useKerning = true;
|
||||||
|
// uv
|
||||||
|
const [u, v] = [index%25*20, (index/25|0)*20];
|
||||||
|
chars.push({x, y, u, v});
|
||||||
|
// next
|
||||||
|
x += width + kerning;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
root: {
|
||||||
|
transform: `translate(${x0}px, ${y0-fontSize}px) scale(${fontSize/20})`,
|
||||||
|
},
|
||||||
|
chars: chars.map(({x, y, u, v}) => {
|
||||||
|
const offset = `${-u}px ${-v}px`;
|
||||||
|
return {
|
||||||
|
ctn: {
|
||||||
|
left: x+'px',
|
||||||
|
top: y+'px',
|
||||||
|
},
|
||||||
|
bg: {
|
||||||
|
'background-position': offset,
|
||||||
|
},
|
||||||
|
mask: {
|
||||||
|
'mask-position': offset,
|
||||||
|
'-webkit-mask-position': offset,
|
||||||
|
background: color,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.preview-str {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.preview-str * {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
div.char-ctn {
|
||||||
|
isolation: isolate;
|
||||||
|
}
|
||||||
|
div.char-ctn > div {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
div.char-bg {
|
||||||
|
background: url(/img/preview/font-jp.png);
|
||||||
|
}
|
||||||
|
div.char-mask {
|
||||||
|
mask-image: url(/img/preview/font-jp.png);
|
||||||
|
-webkit-mask-image: url(/img/preview/font-jp.png);
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
-webkit-mask-repeat: no-repeat;
|
||||||
|
mix-blend-mode: multiply;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -26,7 +26,8 @@ export const defaultConfig = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getConfig() {
|
export function getConfig() {
|
||||||
const config = parseJSON(localStorage.getItem(lskey)) ?? {};
|
const config =
|
||||||
|
(typeof localStorage !== 'undefined' && parseJSON(localStorage.getItem(lskey))) || {};
|
||||||
return {
|
return {
|
||||||
...defaultConfig,
|
...defaultConfig,
|
||||||
...config,
|
...config,
|
||||||
|
|
|
@ -22,21 +22,7 @@
|
||||||
<span>{{l.alpha}}</span><input type="number" min="0" max="255" v-model.number="bgA"><span>/255={{(bgA/2.55).toFixed(1)}}%</span>
|
<span>{{l.alpha}}</span><input type="number" min="0" max="255" v-model.number="bgA"><span>/255={{(bgA/2.55).toFixed(1)}}%</span>
|
||||||
</div>
|
</div>
|
||||||
<h4>{{l.preview}}</h4>
|
<h4>{{l.preview}}</h4>
|
||||||
<svg viewBox="0 16 600 448">
|
<Preview :config="codeConfigs" />
|
||||||
<defs>
|
|
||||||
<linearGradient id="fgColor" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
||||||
<stop offset="0%" :style="{stopColor: rgbI2S(fgRGB), stopOpacity: fgA/255}" />
|
|
||||||
<stop offset="100%" :style="{
|
|
||||||
stopColor: rgbI2S(fgRGB2 == null ? fgRGB : fgRGB2),
|
|
||||||
stopOpacity: (fgA2 == null ? fgA : fgA2)/255,
|
|
||||||
}" />
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<image href="/img/qft/preview-base.jpg" y="16" width="600" height="448" />
|
|
||||||
<rect :x="x" :y="y-fontSize" :width="width*fontSize/20" :height="fontSize" :fill="rgbaI2S(bgRGB, bgA)" />
|
|
||||||
<text :x="x+fontSize/10" :y="y-fontSize/10" fill="url(#fgColor)"
|
|
||||||
:style="{fontSize: fontSize+'px', fontFamily: 'auto'}">0:00.000</text>
|
|
||||||
</svg>
|
|
||||||
<div style="white-space: pre">{{l.previewNote}}</div>
|
<div style="white-space: pre">{{l.previewNote}}</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="freeze">
|
<section class="freeze">
|
||||||
|
@ -58,23 +44,25 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {getConfig, lskey, buttonValues, codes} from './codegen.js';
|
// import Preview from '../../PreviewString.vue';
|
||||||
|
import {getConfig, lskey, codes} from './codegen.js';
|
||||||
import labels from './labels.json';
|
import labels from './labels.json';
|
||||||
import {getLabels} from '../codegen.js';
|
|
||||||
|
|
||||||
function updateConfig() {
|
function updateConfig() {
|
||||||
const {x, y, fontSize, width, fgRGB, fgA, fgRGB2, fgA2, bgRGB, bgA, freeze, freezeDuration} = this;
|
const {x, y, fontSize, width, fgRGB, fgA, fgRGB2, fgA2, bgRGB, bgA, freeze, freezeDuration} = this;
|
||||||
localStorage.setItem(lskey, JSON.stringify({
|
const config = {
|
||||||
x, y, fontSize, width, fgRGB, fgA, fgRGB2, fgA2, bgRGB, bgA, freeze, freezeDuration
|
x, y, fontSize, width, fgRGB, fgA, fgRGB2, fgA2, bgRGB, bgA, freeze, freezeDuration
|
||||||
}));
|
};
|
||||||
|
localStorage.setItem(lskey, JSON.stringify(config));
|
||||||
|
this.$emit('config', config);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
version: {type: String},
|
version: {type: String},
|
||||||
|
codeConfigs: {type: Object},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateConfig,
|
|
||||||
onChangeFreeze($event, key) {
|
onChangeFreeze($event, key) {
|
||||||
this.freeze[key] = $event.target.checked;
|
this.freeze[key] = $event.target.checked;
|
||||||
this.updateConfig();
|
this.updateConfig();
|
||||||
|
|
2450
site/.vuepress/data/font-jp.json
Normal file
2450
site/.vuepress/data/font-jp.json
Normal file
File diff suppressed because it is too large
Load diff
BIN
site/.vuepress/public/img/preview/background.png
Normal file
BIN
site/.vuepress/public/img/preview/background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 505 KiB |
BIN
site/.vuepress/public/img/preview/font-jp.png
Normal file
BIN
site/.vuepress/public/img/preview/font-jp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 74 KiB |
Loading…
Reference in a new issue