|
18 | 18 |
|
19 | 19 | class Surface { |
20 | 20 | constructor(width, height) { |
21 | | - this._o = new OffscreenCanvas(width, height) |
22 | | - this._c = this._o.getContext("2d") |
| 21 | + if (!(Number.isInteger(width) && Number.isInteger(height))) {debugger} |
| 22 | + console.assert(Number.isInteger(width) && Number.isInteger(height), "Surface must have int width/height") |
| 23 | + this.o = new OffscreenCanvas(width, height) |
| 24 | + this._c = this.o.getContext("2d") |
23 | 25 | this._img = undefined |
24 | 26 | } |
| 27 | + get w() {return this.o.width} |
| 28 | + get h() {return this.o.height} |
25 | 29 | get c() {this._img = undefined; return this._c} |
26 | | - get img() {return this._img || (this._img = this._o.transferToImageBitmap())} |
| 30 | + get img() {return this._img || (this._img = this.o.transferToImageBitmap())} |
| 31 | + clear() {this.c.clearRect(0, 0, this.w, this.h)} |
| 32 | + static isDimensionMatch(a, b) {return a.w==b.w && a.h==b.h} |
| 33 | + static fromCanvas(canvas) { |
| 34 | + const s = new Surface(canvas.width, canvas.height) |
| 35 | + s.c.drawImage(canvas,0,0) |
| 36 | + return s |
| 37 | + } |
27 | 38 | } |
28 | 39 |
|
29 | 40 |
|
| 41 | +class SurfaceMix { |
| 42 | + /* |
| 43 | + Mix two Surfaces |
| 44 | + A B Mask Output |
| 45 | + |-----| |-----| |-----| |-----| |
| 46 | + | a | | b | |OOOO/| | a /| |
| 47 | + | | | | |OOO/ | | / | |
| 48 | + | |+| |+|OO/ |=| / | |
| 49 | + | | | | |O/ | | / | |
| 50 | + | a | | b | |/ | |/ b | |
| 51 | + |-----| |-----| |-----| |-----| |
| 52 | + A & B are mutated/modified/cut so they can be drawn to create the Output |
| 53 | + */ |
| 54 | + constructor(surface_a, surface_b, mask) { |
| 55 | + this.a = surface_a |
| 56 | + this.b = surface_b |
| 57 | + this.mask = mask || new Surface(this.a.w, this.a.h) |
| 58 | + console.assert(Surface.isDimensionMatch(this.a, this.b), "Surfaces should match dimension") |
| 59 | + console.assert(Surface.isDimensionMatch(this.a, this.mask), "Mask should match Surface dimension") |
| 60 | + } |
| 61 | + cut() { |
| 62 | + this.a.c.save() |
| 63 | + this.a.c.globalCompositeOperation = 'destination-in'; |
| 64 | + this.a.c.drawImage(this.mask.o, 0, 0) |
| 65 | + this.a.c.restore() |
| 66 | + this.b.c.save() |
| 67 | + this.b.c.globalCompositeOperation = 'destination-out'; |
| 68 | + this.b.c.drawImage(this.mask.o, 0, 0) |
| 69 | + this.b.c.restore() |
| 70 | + } |
| 71 | +} |
| 72 | + |
30 | 73 | class Font { |
31 | 74 | constructor(img) { |
32 | 75 | this.font = this._load_font_advance(img) |
|
63 | 106 | draw_char_mask(c, char, x, y) { |
64 | 107 | let img |
65 | 108 | if (!(img = this.char_cache[char])) { |
66 | | - img = this.render_mask_img(this.font[char], this.background.img) |
| 109 | + img = this.render_mask_img(this.font[char], this.background.o) |
67 | 110 | this.char_cache[char] = img |
68 | 111 | } |
69 | 112 | c.drawImage(img, x, y) |
|
79 | 122 |
|
80 | 123 | class FontCanvas extends CanvasAnimationBase { |
81 | 124 | constructor() { |
82 | | - super(undefined, 60, {background_color: 'black', width: 320, height: 180}) |
| 125 | + super(undefined, 60, {background_color: 'black', width: 480, height: 270}) |
| 126 | + this.a = Surface.fromCanvas(this.canvas) |
| 127 | + this.b = Surface.fromCanvas(this.canvas) |
| 128 | + this.mix = new SurfaceMix(this.a, this.b) |
83 | 129 | } |
84 | 130 |
|
85 | 131 | async constructor_async() { |
86 | | - this.font = new Font(CanvasAnimationBase.invert(await this.load_image("font", "font.webp"))) |
| 132 | + this.font = new Font(CanvasAnimationBase.invert(await this.load_image("font", "Babyteeth.webp"))) |
87 | 133 | } |
88 | 134 |
|
89 | 135 | model_inc(frame) { |
90 | 136 | } |
91 | 137 | draw(context, frame) { |
| 138 | + |
92 | 139 | this.font.clear_cache() |
93 | 140 | const bc = this.font.background.c |
94 | 141 | bc.fillStyle='green'; bc.fillRect(0,0,8,8); |
95 | | - let f = Math.abs(Math.floor(Math.sin(frame/64)*16)) |
| 142 | + let f = Math.abs(Math.floor(Math.sin(frame/64)*15)) |
96 | 143 | CanvasAnimationBase.drawLine(bc,4+f%16,-4,-4,4+f%16,'#00FF00') |
97 | 144 |
|
| 145 | + this.a.clear() |
| 146 | + this.font.draw_font(this.a.c, "Hello, What is this! OMG OMG", 20, 20) |
| 147 | + |
| 148 | + this.b.clear() |
| 149 | + this.b.c.fillStyle='grey' |
| 150 | + this.b.c.fillRect(0,0,this.b.w,this.b.h) |
| 151 | + |
| 152 | + this.mix.mask.clear() |
| 153 | + this.mix.mask.c.fillStyle = 'white' |
| 154 | + this.mix.mask.c.fillRect(0,0,frame%this.w,this.h) |
| 155 | + |
| 156 | + this.mix.cut() |
| 157 | + |
98 | 158 | this.clear() |
99 | | - const c = context |
100 | | - this.font.draw_font(c, "Hello, What is this! OMG OMG", 20, 20) |
| 159 | + context.drawImage(this.a.o,0,0) |
| 160 | + context.drawImage(this.b.o,0,0) |
| 161 | + |
| 162 | + CanvasAnimationBase.drawLine(context, frame%this.w,0,frame%this.w,this.h,'white',4) |
101 | 163 | } |
102 | 164 |
|
103 | 165 |
|
|
0 commit comments