8bitworkshop/src/test/testecs.ts

450 lines
11 KiB
TypeScript

import { describe } from "mocha";
import { ECSCompiler } from "../common/ecs/compiler";
import { Dialect_CA65, EntityManager, SourceFileExport } from "../common/ecs/ecs";
const TEMPLATE1 = `
{{@NextFrame}}:
FRAME_START
{{!preframe}}
KERNEL_START
{{!kernel}}
KERNEL_END
{{!postframe}}
FRAME_END
lsr SWCHB ; test Game Reset switch
bcs @NoStart
jmp Start
@NoStart:
jmp {{@NextFrame}}
`;
// TODO: two sticks?
const TEMPLATE2_a = `
lda SWCHA
sta {{$0}}
`
const TEMPLATE2_b = `
asl {{$0}}
bcs {{@SkipMoveRight}}
{{!joyright}}
{{@SkipMoveRight}}:
asl {{$0}}
bcs {{@SkipMoveLeft}}
{{!joyleft}}
{{@SkipMoveLeft}}:
asl {{$0}}
bcs {{@SkipMoveDown}}
{{!joydown}}
{{@SkipMoveDown}}:
asl {{$0}}
bcs {{@SkipMoveUp}}
{{!joyup}}
{{@SkipMoveUp}}:
`;
const TEMPLATE3_L = `
lda {{<xpos}}
sec
sbc #1
bcc {{@nomove}}
sta {{<xpos}}
{{@nomove}}:
`;
const TEMPLATE3_R = `
lda {{<xpos}}
clc
adc #1
cmp #150
bcs {{@nomove}}
sta {{<xpos}}
{{@nomove}}:
`;
const TEMPLATE3_U = `
lda {{<ypos}}
sec
sbc #1
bcc {{@nomove}}
sta {{<ypos}}
{{@nomove}}:
`;
const TEMPLATE3_D = `
lda {{<ypos}}
clc
adc #1
cmp #150
bcs {{@nomove}}
sta {{<ypos}}
{{@nomove}}:
`;
const TEMPLATE4_S1 = `
.macro {{@KernelSetup}} ent,ofs
lda #192 ; TODO: numlines
sec
sbc ypos_ypos_b0+ent
sta {{$5}}+ofs
ldy hasbitmap_bitmap_b0+ent
lda bitmap_bitmapdata_b0,y
sec
sbc {{$5}}+ofs
sta {{$0}}+ofs
lda bitmap_bitmapdata_b8,y
sbc #0
sta {{$1}}+ofs
ldy hascolormap_colormap_b0+ent
lda colormap_colormapdata_b0,y
sec
sbc {{$5}}+ofs
sta {{$2}}+ofs
lda colormap_colormapdata_b8,y
sbc #0
sta {{$3}}+ofs
lda sprite_height_b0+ent
sta {{$4}}+ofs
lda ypos_ypos_b0+ent
sta {{$5}}+ofs
.endmacro
`
const TEMPLATE4_S2 = `
{{@KernelSetup}} 0,0
{{@KernelSetup}} 1,6
`
// https://atariage.com/forums/topic/75982-skipdraw-and-graphics/?tab=comments#comment-928232
// https://atariage.com/forums/topic/129683-advice-on-a-masking-kernel/
// https://atariage.com/forums/topic/128147-having-trouble-with-2-free-floating-player-graphics/?tab=comments#comment-1547059
const TEMPLATE4_K = `
lda {{<bgcolor}}
sta COLUBK
ldy {{<lines}}
@LVScan:
lda {{$4}} ; height
dcp {{$5}}
bcs @DoDraw1
lda #0
.byte $2C
@DoDraw1:
lda ({{$0}}),y
sta WSYNC
sta GRP0
lda ({{$2}}),y
sta COLUP0
lda {{$10}} ; height
dcp {{$11}}
bcs @DoDraw2
lda #0
.byte $2C
@DoDraw2:
lda ({{$6}}),y
sta GRP1
lda ({{$8}}),y
sta COLUP1
dey ; decrement
bne @LVScan ; repeat until 192 lines
`;
const SET_XPOS = `
lda {{<xpos}}
ldy {{<plyrindex}}
sta HMCLR
jsr {{^SetHorizPos}}
`
const SETHORIZPOS = `
; SetHorizPos routine
; A = X coordinate
; Y = player number (0 or 1)
SetHorizPos:
sta WSYNC ; start a new line
sec ; set carry flag
nop
@DivideLoop:
sbc #15 ; subtract 15
bcs @DivideLoop ; branch until negative
eor #7 ; calculate fine offset
asl
asl
asl
asl
sta RESP0,y ; fix coarse position
sta HMP0,y ; set fine offset
sta WSYNC
sta HMOVE
rts ; return to caller
`
const INITFROMSPARSE = `
MemSrc equ $80
MemDest equ $82
InitMemory:
ldy #0
lda (MemSrc),y
beq .done
tax
iny
lda (MemSrc),y
sta MemDest
iny
lda (MemSrc),y
sta MemDest+1
.loop
iny
lda (MemSrc),y
sta (MemDest),y
dex
bne .loop
.done rts
`
function testECS() {
let em = new EntityManager(new Dialect_CA65());
let c_kernel = em.defineComponent({
name: 'kernel', fields: [
{ name: 'lines', dtype: 'int', lo: 0, hi: 255 },
{ name: 'bgcolor', dtype: 'int', lo: 0, hi: 255 },
]
})
let c_sprite = em.defineComponent({
name: 'sprite', fields: [
{ name: 'height', dtype: 'int', lo: 0, hi: 255 },
{ name: 'plyrindex', dtype: 'int', lo: 0, hi: 1 },
]
})
let c_plyrflags = em.defineComponent({
name: 'nusizable', fields: [
{ name: 'plyrflags', dtype: 'int', lo: 0, hi: 63 },
]
})
let c_player = em.defineComponent({
name: 'player', fields: [
//TODO: optional?
]
})
let c_hasbitmap = em.defineComponent({
name: 'hasbitmap', fields: [
{ name: 'bitmap', dtype: 'ref', query: { include: ['bitmap'] } },
]
})
let c_hascolormap = em.defineComponent({
name: 'hascolormap', fields: [
{ name: 'colormap', dtype: 'ref', query: { include: ['colormap'] } },
]
})
let c_bitmap = em.defineComponent({
name: 'bitmap', fields: [
{ name: 'bitmapdata', dtype: 'array', elem: { dtype: 'int', lo: 0, hi: 255 } }
]
})
let c_colormap = em.defineComponent({
name: 'colormap', fields: [
{ name: 'colormapdata', dtype: 'array', elem: { dtype: 'int', lo: 0, hi: 255 } }
]
})
let c_xpos = em.defineComponent({
name: 'xpos', fields: [
{ name: 'xpos', dtype: 'int', lo: 0, hi: 255 }
]
})
let c_ypos = em.defineComponent({
name: 'ypos', fields: [
{ name: 'ypos', dtype: 'int', lo: 0, hi: 255 }
]
})
let c_xyvel = em.defineComponent({
name: 'xyvel', fields: [
{ name: 'xvel', dtype: 'int', lo: -8, hi: 7 },
{ name: 'yvel', dtype: 'int', lo: -8, hi: 7 }
]
})
// init -> [start] -> frameloop
// frameloop -> [preframe] [kernel] [postframe]
// temp between preframe + frame?
// TODO: check names for identifierness
em.defineSystem({
name: 'kernel_simple',
tempbytes: 8,
actions: [
{
text: TEMPLATE4_S1, event: 'preframe', select: 'once', query: {
include: ['kernel']
}
},
{
// TODO: should include kernel for numlines
text: TEMPLATE4_S2, event: 'preframe', select: 'once', query: {
include: ['sprite', 'hasbitmap', 'hascolormap', 'ypos'],
},
},
{
text: TEMPLATE4_K, event: 'kernel', select: 'once', query: {
include: ['kernel']
}
},
]
})
em.defineSystem({
name: 'set_xpos',
actions: [
{
text: SET_XPOS, event: 'preframe', select: 'each', query: {
include: ['sprite', 'xpos']
},
},
//{ text:SETHORIZPOS },
]
})
// https://docs.unity3d.com/Packages/com.unity.entities@0.17/manual/ecs_systems.html
em.defineSystem({
name: 'frameloop',
emits: ['preframe', 'kernel', 'postframe'],
actions: [
{ text: TEMPLATE1, event: 'start', select: 'once', query: { include: ['kernel'] } }
]
})
em.defineSystem({
name: 'joyread',
tempbytes: 1,
emits: ['joyup', 'joydown', 'joyleft', 'joyright', 'joybutton'],
actions: [
{ text: TEMPLATE2_a, event: 'postframe', select: 'once', query: { include: ['player'] } },
{ text: TEMPLATE2_b, event: 'postframe', select: 'each', query: { include: ['player'] } }
]
});
em.defineSystem({
name: 'move_x',
actions: [
{ text: TEMPLATE3_L, event: 'joyleft', select: 'source', query: { include: ['player', 'xpos'] }, },
{ text: TEMPLATE3_R, event: 'joyright', select: 'source', query: { include: ['player', 'xpos'] }, },
]
});
em.defineSystem({
name: 'move_y',
actions: [
{ text: TEMPLATE3_U, event: 'joyup', select: 'source', query: { include: ['player', 'ypos'] } },
{ text: TEMPLATE3_D, event: 'joydown', select: 'source', query: { include: ['player', 'ypos'] } },
]
});
em.defineSystem({
name: 'SetHorizPos',
actions: [
{ text: SETHORIZPOS, event: 'SetHorizPos', select: 'once', query: { include: ['xpos'] } },
]
});
let root = em.newScope("Root");
let scene = em.newScope("Scene", root);
let e_ekernel = root.newEntity({ components: [c_kernel] });
root.setConstValue(e_ekernel, c_kernel, 'lines', 192);
//root.setConstValue(e_ekernel, c_kernel, 'bgcolor', 0x92);
root.setInitValue(e_ekernel, c_kernel, 'bgcolor', 0x92);
let e_bitmap0 = root.newEntity({ components: [c_bitmap] });
// TODO: store array sizes?
root.setConstValue(e_bitmap0, c_bitmap, 'bitmapdata', new Uint8Array([1, 1, 3, 7, 15, 31, 63, 127]));
let e_colormap0 = root.newEntity({ components: [c_colormap] });
root.setConstValue(e_colormap0, c_colormap, 'colormapdata', new Uint8Array([6, 3, 6, 9, 12, 14, 31, 63]));
let ea_playerSprite = { components: [c_sprite, c_hasbitmap, c_hascolormap, c_xpos, c_ypos, c_player] };
let e_player0 = root.newEntity(ea_playerSprite);
root.setConstValue(e_player0, c_sprite, 'plyrindex', 0);
root.setInitValue(e_player0, c_sprite, 'height', 8);
root.setInitValue(e_player0, c_xpos, 'xpos', 50);
root.setInitValue(e_player0, c_ypos, 'ypos', 50);
let e_player1 = root.newEntity(ea_playerSprite);
root.setConstValue(e_player1, c_sprite, 'plyrindex', 1);
root.setInitValue(e_player1, c_sprite, 'height', 8);
root.setInitValue(e_player1, c_xpos, 'xpos', 100);
root.setInitValue(e_player1, c_ypos, 'ypos', 60);
//console.log(em.archetypesMatching({ include:['xpos','ypos']})[0])
root.analyzeEntities();
root.generateCode();
let src = new SourceFileExport();
root.dump(src);
//console.log(src.toString());
//console.log(em.toYAML());
}
function testCompiler() {
let c = new ECSCompiler();
try {
c.parseFile(`
component Kernel
lines: 0..255
bgcolor: 0..255
end
component Bitmap
data: array of 0..255
end
component HasBitmap
bitmap: [Bitmap]
end
system SimpleKernel
locals 8
on preframe do once [Kernel] --- JUNK_AT_END
lda #5
sta #6
Label:
---
end
scope Root
entity kernel [Kernel]
const lines = 100
end
entity player1 [HasBitmap]
const plyrindex = 0
init height = 8
init xpos = 100
init ypos = 100
end
end
`, 'foo.txt');
console.log('json', c.em.toJSON());
let src = new SourceFileExport();
c.exportToFile(src);
// TODO: test?
//console.log(src.toString());
} catch (e) {
console.log(e);
for (let err of c.errors) {
console.log(err);
}
console.log(c.tokens);
}
}
// TODO: files in markdown?
// TODO: jsr OperModeExecutionTree?
describe('Tokenizer', function() {
it('Should use API', function() {
testECS();
});
it('Should use Compiler', function() {
testCompiler();
});
});