]> 4ch.mooo.com Git - plz.git/blob - Plasma.js
dots for a simple port but damn it!
[plz.git] / Plasma.js
1 var SCREEN_WIDTH = 320;\r
2 var SCREEN_HEIGHT = 400;\r
3 var FRAME_BUFFER_WIDTH = 384;\r
4 var FRAME_BUFFER_HEIGHT = 400;\r
5 var PLANE_COUNT = 4;\r
6 var COLOURS_PER_ENTRY = 3;\r
7 var DPII = (3.1415926535*2.0);\r
8 var MAXY = 280;\r
9 \r
10 var g_au8FrameBuffer = new Uint8Array(FRAME_BUFFER_WIDTH * FRAME_BUFFER_HEIGHT);\r
11 var s_abSelectedPlanes = [ false, false, false, false ];\r
12 var s_nLineCompareY = 0;\r
13 var s_nHorizontalScrollOffset = 0;\r
14 var s_au8Palette = new Uint8Array(256 * COLOURS_PER_ENTRY);\r
15 var frame_count = 0;\r
16 var cop_drop = 0;\r
17 var do_pal = 0;\r
18 var cop_start = 0;\r
19 var cop_scrl = 0;\r
20 var cop_plz = 1;\r
21 var pompi = 0;\r
22 var dtau = new Array();\r
23 var fadepal = new Uint8Array(768 * 2);\r
24 var cop_fadepal_SelectedPaletteIndex = 0;\r
25 var anSelfModifyOffsets = new Uint16Array(5 * 84);\r
26 \r
27 // [NK 8/1/2014] The assembly code assumes the tables are sequential in memory,\r
28 // [NK 8/1/2014] so merge them into one array to be safe.\r
29 var psini = new Uint8Array(16384 + (8192 * 2) + (8192 * 2));\r
30 var psini_DataView = new DataView(psini.buffer);\r
31 var ptau = new Uint8Array(256);\r
32 var pals = new Uint16Array(6 * 768);\r
33 var pals_DataView = new DataView(pals.buffer);\r
34 \r
35 var curpal=0;\r
36 var timetable=[64*6*2-45,64*6*4-45,64*6*5-45,64*6*6-45,64*6*7+90,0];\r
37 var ttptr=0;\r
38 \r
39 var     l1=1000, l2=2000, l3=3000, l4=4000;\r
40 var     k1=3500, k2=2300, k3=3900, k4=3670;\r
41 \r
42 var     il1=1000, il2=2000, il3=3000, il4=4000;\r
43 var     ik1=3500, ik2=2300, ik3=3900, ik4=3670;\r
44 \r
45 var inittable = new Array();\r
46 var IsComplete = false;\r
47 \r
48 //--------------------------------------------------------------------------------------\r
49 // Variable wrappers\r
50 \r
51 function Palette_WriteByte(nOffset, u8Byte)\r
52 {\r
53         s_au8Palette[nOffset] = u8Byte;\r
54 }\r
55 \r
56 function Palette_ReadByte(nOffset)\r
57 {\r
58         return s_au8Palette[nOffset];\r
59 }\r
60 \r
61 function FrameBuffer_WriteByte(nOffset, u8Byte)\r
62 {\r
63         g_au8FrameBuffer[nOffset] = u8Byte;\r
64 }\r
65 \r
66 function FrameBuffer_ReadByte(nOffset)\r
67 {\r
68         return g_au8FrameBuffer[nOffset];\r
69 }\r
70 \r
71 function lsini16_GetOffset()\r
72 {\r
73         return 16384 + (8192 * 2);\r
74 }\r
75 \r
76 function lsini4_GetOffset()\r
77 {\r
78         return 16384;\r
79 }\r
80 \r
81 function cop_fadepal_SetSelectedPaletteIndex(nIndex)\r
82 {\r
83         cop_fadepal_SelectedPaletteIndex = nIndex;\r
84 }\r
85 \r
86 function cop_fadepal_ReadWord(nByteOffset)\r
87 {\r
88         // Advance to the currently selected palette.\r
89         nByteOffset += (cop_fadepal_SelectedPaletteIndex * 768 * 2);\r
90 \r
91         return pals_DataView.getUint16(nByteOffset);\r
92 }\r
93 \r
94 function fadepal_ReadByte(nByteOffset)\r
95 {\r
96         return fadepal[nByteOffset];\r
97 }\r
98 \r
99 function fadepal_WriteByte(nByteOffset, nValue)\r
100 {\r
101         fadepal[nByteOffset] = nValue;\r
102 }\r
103 \r
104 function lsini4_WriteWord(nIndex, nValue)\r
105 {\r
106         var nByteOffset = lsini4_GetOffset() + (nIndex * 2);\r
107         psini_WriteWord(nByteOffset, nValue);\r
108 }\r
109 \r
110 function lsini16_WriteWord(nIndex, nValue)\r
111 {\r
112         var nByteOffset = lsini16_GetOffset() + (nIndex * 2);\r
113         psini_WriteWord(nByteOffset, nValue);\r
114 }\r
115 \r
116 function psini_WriteByte(nIndex, nValue)\r
117 {\r
118         psini[nIndex] = nValue;\r
119 }\r
120 \r
121 function psini_ReadByte(nIndex, nValue)\r
122 {\r
123         return psini[nIndex];\r
124 }\r
125 \r
126 function psini_WriteWord(nByteOffset, nValue) {\r
127         psini_DataView.setUint16(nByteOffset, nValue);\r
128 }\r
129 \r
130 function psini_ReadWord(nByteOffset, nValue) {\r
131         return psini_DataView.getUint16(nByteOffset);\r
132 }\r
133 \r
134 function ptau_WriteByte(nIndex, nValue)\r
135 {\r
136         ptau[nIndex] = nValue;\r
137 }\r
138 \r
139 function ptau_ReadByte(nIndex)\r
140 {\r
141         return ptau[nIndex];\r
142 }\r
143 \r
144 function pal_WriteWord(nByteOffset, nWord)\r
145 {\r
146         pals_DataView.setUint16(nByteOffset, nWord);\r
147 }\r
148 \r
149 function pal_ReadWord(nByteOffset)\r
150 {\r
151         return pals_DataView.getUint16(nByteOffset);\r
152 }\r
153 \r
154 function fadepal_Clear()\r
155 {\r
156         for (var i = 0; i < 768; i++)\r
157         {\r
158                 fadepal[i] = 0;\r
159         }\r
160 }\r
161 \r
162 function fadepal_ClearToWhite() {\r
163         for (var i = 0; i < 768; i++) {\r
164                 fadepal[i] = 63;\r
165         }\r
166 }\r
167 \r
168 function anSelfModifyOffsets_ReadWord(nOffset)\r
169 {\r
170         return anSelfModifyOffsets[nOffset];\r
171 }\r
172 \r
173 function anSelfModifyOffsets_WriteWord(nOffset, nValue)\r
174 {\r
175         anSelfModifyOffsets[nOffset] = nValue;\r
176 }\r
177 \r
178 //--------------------------------------------------------------------------------------\r
179 // SDL\r
180 \r
181 function SDL_SetPixel(x, y, color)\r
182 {\r
183         var pixels = image.data;\r
184         var nOffset = (((y * 320) + x) * 4);\r
185         pixels[nOffset] = (color >> 0) & 0xFF;\r
186         nOffset++;\r
187         pixels[nOffset] = (color >> 8) & 0xFF;\r
188         nOffset++;\r
189         pixels[nOffset] = (color >> 16) & 0xFF;\r
190         nOffset++;\r
191         pixels[nOffset] = 0xFF;\r
192         nOffset++;\r
193 }\r
194 \r
195 function SDL_SetPixelColours(x, y, nRed, nGreen, nBlue)\r
196 {\r
197         var pixels = image.data;\r
198         var nOffset = (((y * 320) + x) * 4);\r
199         pixels[nOffset] = (nRed) & 0xFF;\r
200         nOffset++;\r
201         pixels[nOffset] = (nGreen) & 0xFF;\r
202         nOffset++;\r
203         pixels[nOffset] = (nBlue) & 0xFF;\r
204         nOffset++;\r
205         pixels[nOffset] = 0xFF;\r
206         nOffset++;\r
207 }\r
208 \r
209 //--------------------------------------------------------------------------------------\r
210 // VGA\r
211 \r
212 function VGA_SelectBitPlanes02()\r
213 {\r
214         s_abSelectedPlanes[0] = true;\r
215         s_abSelectedPlanes[1] = false;\r
216         s_abSelectedPlanes[2] = true;\r
217         s_abSelectedPlanes[3] = false;\r
218 }\r
219 \r
220 function VGA_SelectBitPlanes13()\r
221 {\r
222         s_abSelectedPlanes[0] = false;\r
223         s_abSelectedPlanes[1] = true;\r
224         s_abSelectedPlanes[2] = false;\r
225         s_abSelectedPlanes[3] = true;\r
226 }\r
227 \r
228 function VGA_SelectBitPlanes0123()\r
229 {\r
230         s_abSelectedPlanes[0] = true;\r
231         s_abSelectedPlanes[1] = true;\r
232         s_abSelectedPlanes[2] = true;\r
233         s_abSelectedPlanes[3] = true;\r
234 }\r
235 \r
236 function VGA_WriteDword(nOffset, uValue)\r
237 {\r
238         // For each selected plane, calculate 4 pixel offsets and write 4 bytes.\r
239         // nOffset = 0, 4, 8, etc\r
240 \r
241         for (var nPlaneIndex = 0; nPlaneIndex < PLANE_COUNT; nPlaneIndex++)\r
242         {\r
243                 if (s_abSelectedPlanes[nPlaneIndex])\r
244                 {\r
245                         for (var nPixelIndex = 0; nPixelIndex < 4; nPixelIndex++)\r
246                         {\r
247                                 // Get byte to write.\r
248                                 var u8Byte = (uValue >> (nPixelIndex * 8)) & 0xFF;\r
249 \r
250                                 // Calculate offset.\r
251                                 var nFrameBufferOffset = nPlaneIndex + (nOffset * 4) + (nPixelIndex * 4);\r
252 \r
253                                 // Write pixel.\r
254                                 FrameBuffer_WriteByte(nFrameBufferOffset, u8Byte);\r
255                         }\r
256                 }\r
257         }\r
258 }\r
259 \r
260 function VGA_SetLineCompare(nY)\r
261 {\r
262         s_nLineCompareY = nY;\r
263 }\r
264 \r
265 function VGA_SetPaletteEntry(nIndex, u8Red, u8Green, u8Blue)\r
266 {\r
267         var nOffset = 0;\r
268 \r
269         nOffset = (nIndex * 3) + 0;\r
270         Palette_WriteByte(nOffset, u8Red);\r
271 \r
272         nOffset = (nIndex * 3) + 1;\r
273         Palette_WriteByte(nOffset, u8Green);\r
274 \r
275         nOffset = (nIndex * 3) + 2;\r
276         Palette_WriteByte(nOffset, u8Blue);\r
277 }\r
278 \r
279 function VGA_ShowFrameBuffer()\r
280 {\r
281         copper1();\r
282         copper2();\r
283 \r
284         var nFirstLineIndex = (s_nLineCompareY + 1);\r
285 \r
286         // Plot the palettised frame buffer.\r
287         var nFrameBufferOffset = 0;\r
288 \r
289         for (var nY = nFirstLineIndex; nY < SCREEN_HEIGHT; nY++)\r
290         {\r
291                 for (var nX = 0; nX < SCREEN_WIDTH; nX++)\r
292                 {\r
293                         //ASSERT(nX + s_nHorizontalScrollOffset < FRAME_BUFFER_WIDTH);\r
294                         var nPaletteIndex = FrameBuffer_ReadByte(nFrameBufferOffset + nX + s_nHorizontalScrollOffset);\r
295 \r
296                         var nPaletteOffset = 0;\r
297                         nPaletteOffset = (nPaletteIndex * 3) + 0;\r
298                         var nRed = Palette_ReadByte(nPaletteOffset);\r
299                         nPaletteOffset = (nPaletteIndex * 3) + 1;\r
300                         var nGreen = Palette_ReadByte(nPaletteOffset);\r
301                         nPaletteOffset = (nPaletteIndex * 3) + 2;\r
302                         var nBlue = Palette_ReadByte(nPaletteOffset);\r
303 \r
304                         // [NK 12/1/2014] VGA colours range from 0 - 63 inclusive, but\r
305                         // [NK 12/1/2014] SDL colours range from 0 - 255 inclusive, so\r
306                         // [NK 12/1/2014] account for this here.\r
307                         nRed &= 63;\r
308                         nGreen &= 63;\r
309                         nBlue &= 63;\r
310 \r
311                         nRed *= 255;\r
312                         nRed /= 63;\r
313                         nGreen *= 255;\r
314                         nGreen /= 63;\r
315                         nBlue *= 255;\r
316                         nBlue /= 63;\r
317 \r
318                         SDL_SetPixelColours(nX, nY, nRed, nGreen, nBlue);\r
319                 }\r
320 \r
321                 nFrameBufferOffset += FRAME_BUFFER_WIDTH;\r
322         }\r
323 }\r
324 \r
325 function VGA_SetHorizontalScrollOffset(nOffset)\r
326 {\r
327         s_nHorizontalScrollOffset = nOffset;\r
328 }\r
329 \r
330 function VGA_UploadPalette(Palette)\r
331 {\r
332         var Source = new Uint8Array(Palette.buffer, 0, 768);\r
333         var Destination = s_au8Palette;\r
334         Destination.set(Source);\r
335 }\r
336 \r
337 //--------------------------------------------------------------------------------------\r
338 // Tweak\r
339 \r
340 function tw_setrgbpalette(pal, r, g, b)\r
341 {\r
342         VGA_SetPaletteEntry(pal, r, g, b);\r
343 }\r
344 \r
345 //--------------------------------------------------------------------------------------\r
346 // Asmyt\r
347 \r
348 function plzline(y, vseg)\r
349 {\r
350         // vseg represented a segment, so multiply by sixteen (shift left by 4)\r
351         // to convert into an offset.\r
352         var nVgaYOffset = vseg * 16;\r
353 \r
354         var cccTable =\r
355         [\r
356                 3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12,19,18,17,16,23,22,21,20,27,26,25,24,31,30,29,28,35,34,33,32,39,38,37,36,43,42,41,40,47,46,45,44,51,50,49,48,55,54,53,52,59,58,57,56,63,62,61,60,67,66,65,64,71,70,69,68,75,74,73,72,79,78,77,76,83,82,81,80\r
357         ];\r
358         var nCount = 84;\r
359 \r
360         var ah = 0;\r
361         var al = 0;\r
362         var eax = 0;\r
363 \r
364         for (var nIndex = 0; nIndex < nCount; nIndex++)\r
365         {\r
366                 var ccc = cccTable[nIndex];\r
367 \r
368                 if ((ccc & 1) == 1)\r
369                 {\r
370                         var nByteOffset = 0;\r
371                         var bx = 0;\r
372 \r
373                         nByteOffset = (y * 2) + anSelfModifyOffsets_ReadWord((2 * 84) + ccc);\r
374                         nByteOffset &= 0xFFFF;\r
375                         bx = psini_ReadWord(nByteOffset);\r
376 \r
377                         nByteOffset = bx + anSelfModifyOffsets_ReadWord((1 * 84) + ccc);\r
378                         nByteOffset &= 0xFFFF;\r
379                         ah = psini_ReadByte(nByteOffset);\r
380 \r
381                         nByteOffset = (y * 2) + anSelfModifyOffsets_ReadWord((4 * 84) + ccc);\r
382                         nByteOffset &= 0xFFFF;\r
383                         bx = psini_ReadWord(nByteOffset);\r
384 \r
385                         nByteOffset = bx + (y * 2) + anSelfModifyOffsets_ReadWord((3 * 84) + ccc);\r
386                         nByteOffset &= 0xFFFF;\r
387                         ah += psini_ReadByte(nByteOffset);\r
388                         ah &= 0xFF;\r
389                 }\r
390                 else\r
391                 {\r
392                         var nByteOffset = 0;\r
393                         var bx = 0;\r
394 \r
395                         nByteOffset = (y * 2) + anSelfModifyOffsets_ReadWord((2 * 84) + ccc);\r
396                         nByteOffset &= 0xFFFF;\r
397                         bx = psini_ReadWord(nByteOffset);\r
398 \r
399                         nByteOffset = bx + anSelfModifyOffsets_ReadWord((1 * 84) + ccc);\r
400                         nByteOffset &= 0xFFFF;\r
401                         al = psini_ReadByte(nByteOffset);\r
402 \r
403                         nByteOffset = (y * 2) + anSelfModifyOffsets_ReadWord((4 * 84) + ccc);\r
404                         nByteOffset &= 0xFFFF;\r
405                         bx = psini_ReadWord(nByteOffset);\r
406 \r
407                         nByteOffset = bx + (y * 2) + anSelfModifyOffsets_ReadWord((3 * 84) + ccc);\r
408                         nByteOffset &= 0xFFFF;\r
409                         al += psini_ReadByte(nByteOffset);\r
410                         al &= 0xFF;\r
411                 }\r
412 \r
413                 if ((ccc & 3) == 2)\r
414                 {\r
415                         eax = (ah << 8) | (al << 0);\r
416                         eax <<= 16;\r
417                 }\r
418 \r
419                 if ((ccc & 3) == 0)\r
420                 {\r
421                         eax |= (ah << 8) | (al << 0);\r
422 \r
423                         VGA_WriteDword(nVgaYOffset + ccc, eax);\r
424                 }\r
425         }\r
426 \r
427         return 0;\r
428 }\r
429 \r
430 function setplzparas(c1, c2, c3, c4)\r
431 {\r
432         var psiniOffset = 0;\r
433         var lsini16Offset = lsini16_GetOffset();\r
434         var lsini4Offset = lsini4_GetOffset();\r
435 \r
436         for (var ccc = 0; ccc < 84; ccc++)\r
437         {\r
438                 var lc1 = c1 + psiniOffset + (ccc * 8);\r
439                 lc1 &= 0xFFFF;\r
440                 anSelfModifyOffsets_WriteWord((1 * 84) + ccc, lc1);\r
441 \r
442                 var lc2 = (c2 * 2) + lsini16Offset - (ccc * 8) + (80 * 8); \r
443                 lc2 &= 0xFFFF;\r
444                 anSelfModifyOffsets_WriteWord((2 * 84) + ccc, lc2);\r
445 \r
446                 var lc3 = c3 + psiniOffset - (ccc * 4) + (80 * 4);\r
447                 lc3 &= 0xFFFF;\r
448                 anSelfModifyOffsets_WriteWord((3 * 84) + ccc, lc3);\r
449 \r
450                 var lc4 = (c4 * 2) + lsini4Offset + (ccc * 32);\r
451                 lc4 &= 0xFFFF;\r
452                 anSelfModifyOffsets_WriteWord((4 * 84) + ccc, lc4);\r
453         }       \r
454 \r
455         return 0;\r
456 }\r
457 \r
458 function set_plzstart(start)\r
459 {\r
460         VGA_SetLineCompare(start);\r
461 \r
462         return 0;\r
463 }\r
464 \r
465 \r
466 //--------------------------------------------------------------------------------------\r
467 // Copper\r
468 \r
469 function init_copper()\r
470 {\r
471         for (var ccc = 0; ccc < 65; ccc++)\r
472         {\r
473                 dtau[ccc] = Math.floor(ccc * ccc / 4 * 43 / 128 + 60);\r
474         }\r
475 \r
476         return 0;\r
477 }\r
478 \r
479 function close_copper()\r
480 {\r
481         return 0;\r
482 }\r
483 \r
484 function pompota() {\r
485 \r
486         // [NK 18/1/2014] Disable this for now, as it looks a bit jittery.\r
487         return;\r
488 \r
489         // [nk] This function toggles the horizontal split point every frame\r
490         // [nk] between line 60 and 61, along with the horizontal offset.\r
491         // [nk] (since set_plzstart == 60, it's splitting at the top of the plasma)\r
492         VGA_SetLineCompare(60);\r
493         cop_scrl = 4;\r
494 \r
495         pompi++;\r
496 \r
497         if ((pompi & 1) != 0)\r
498         {\r
499                 // [NK 12/1/2014] Moving the starting line up and down each alternate frame\r
500                 // [NK 12/1/2014] doesn't look good in windowed mode.\r
501                 // [NK 13/1/2014] Seems to work okay in fullscreen mode though.\r
502                 //VGA_SetLineCompare(61);\r
503                 cop_scrl = 0;\r
504         }\r
505 }\r
506 \r
507 function moveplz()\r
508 {\r
509         k1 += -3;\r
510         k1 &= 4095;\r
511         k2 += -2;\r
512         k2 &= 4095;\r
513         k3 += 1;\r
514         k3 &= 4095;\r
515         k4 += 2;\r
516         k4 &= 4095;\r
517         l1 += -1;\r
518         l1 &= 4095;\r
519         l2 += -2;\r
520         l2 &= 4095;\r
521         l3 += 2;\r
522         l3 &= 4095;\r
523         l4 += 3;\r
524         l4 &= 4095;\r
525 }\r
526 \r
527 function initpparas()\r
528 {\r
529         l1 = il1;\r
530         l2 = il2;\r
531         l3 = il3;\r
532         l4 = il4;\r
533 \r
534         k1 = ik1;\r
535         k2 = ik2;\r
536         k3 = ik3;\r
537         k4 = ik4;\r
538 }\r
539 \r
540 function do_drop()\r
541 {\r
542         cop_drop++;\r
543 \r
544         if (cop_drop <= 64)\r
545         {\r
546                 VGA_SetLineCompare(dtau[cop_drop]);\r
547         }\r
548         else\r
549         {\r
550                 var bShouldFade = false;\r
551 \r
552                 // [NK 18/1/2014] Hack for looping back to the first plasma.\r
553                 if ((cop_drop == 65) && (ttptr == 0)) {\r
554                         cop_drop = 128;\r
555                 }\r
556 \r
557                 if (cop_drop >= 256)\r
558                 {\r
559                 }\r
560                 else if (cop_drop >= 128)\r
561                 {\r
562                         bShouldFade = true;\r
563                 }\r
564                 else if (cop_drop > 96)\r
565                 {\r
566                 }\r
567                 else //if (cop_drop > 64)\r
568                 {\r
569                         bShouldFade = true;\r
570                 }\r
571 \r
572                 if (bShouldFade)\r
573                 {\r
574                         // [NK 15/1/2014] cop_pal always points to fadepal, so just upload fadepal.\r
575                         //cop_pal = fadepal;\r
576                         do_pal = 1;\r
577 \r
578                         if (cop_drop == 65)\r
579                         {\r
580                                 VGA_SetLineCompare(400);\r
581                                 initpparas();\r
582                         }\r
583                         else\r
584                         {\r
585                                 VGA_SetLineCompare(60);\r
586 \r
587                                 // [NK 9/1/2014] I think it's using 8.8 fixed point numbers to fade the palette.\r
588                                 var cop_fadepalIndex = 0;\r
589                                 var pfadepalIndex = 0;\r
590 \r
591                                 for (var nIndex = 0; nIndex < (768 / 16); nIndex++)\r
592                                 {\r
593                                         for (var ccc = 0; ccc < 16; ccc++)\r
594                                         {\r
595                                                 // var al = cop_fadepal_ReadByte(cop_fadepalIndex + (ccc * 2));\r
596                                                 // al &= 0xFF;\r
597                                                 // var ah = cop_fadepal_ReadByte(cop_fadepalIndex + (ccc * 2) + 1);\r
598                                                 // ah &= 0xFF;\r
599                                                 // [NK 17/1/2014] Read cop_fadepal as words, rather than bytes,\r
600                                                 // [NK 17/1/2014] to avoid endian issues.\r
601                                                 var ax = cop_fadepal_ReadWord(cop_fadepalIndex + (ccc * 2));\r
602                                                 var al = ax & 0xFF;\r
603                                                 var ah = (ax >> 8) & 0xFF;\r
604 \r
605                                                 var nOldValue = fadepal_ReadByte(pfadepalIndex + ccc + 768);\r
606                                                 nOldValue &= 0xFF;\r
607 \r
608                                                 var t = fadepal_ReadByte(pfadepalIndex + ccc + 768);\r
609                                                 t &= 0xFF;\r
610                                                 t += al;\r
611                                                 t &= 0xFF;\r
612                                                 fadepal_WriteByte(pfadepalIndex + ccc + 768, t);\r
613 \r
614                                                 var nNewValue = fadepal_ReadByte(pfadepalIndex + ccc + 768);\r
615                                                 nNewValue &= 0xFF;\r
616 \r
617                                                 var nCarry = 0;\r
618 \r
619                                                 if (nNewValue < nOldValue)\r
620                                                 {\r
621                                                         nCarry = 1;\r
622                                                 }\r
623 \r
624                                                 t = fadepal_ReadByte(pfadepalIndex + ccc);\r
625                                                 t &= 0xFF;\r
626                                                 t += ah + nCarry;\r
627                                                 t &= 0xFF;\r
628                                                 fadepal_WriteByte(pfadepalIndex + ccc, t);\r
629                                         }\r
630 \r
631                                         cop_fadepalIndex += 32;\r
632                                         pfadepalIndex += 16;\r
633                                 }\r
634                         }\r
635                 }\r
636                 else\r
637                 {\r
638                         cop_drop = 0;\r
639                 }\r
640         }\r
641 }\r
642 \r
643 // [nk] just before retrace\r
644 function copper1()\r
645 {\r
646         // There is also assembly code to set the first pixel of\r
647         // display memory here, but it may not be necessary.\r
648 \r
649         VGA_SetHorizontalScrollOffset(cop_scrl);\r
650 }\r
651 \r
652 // [nk] in retrace\r
653 function copper2()\r
654 {\r
655         // [nk] Don't think this is used.\r
656         frame_count++;\r
657 \r
658         if (do_pal != 0)\r
659         {\r
660                 do_pal = 0;\r
661                 // [NK 15/1/2014] cop_pal always points to fadepal, so just upload fadepal.\r
662                 //VGA_UploadPalette(cop_pal);\r
663                 VGA_UploadPalette(fadepal);\r
664         }\r
665 \r
666         pompota();\r
667         moveplz();\r
668 \r
669         if (cop_drop != 0)\r
670         {\r
671                 do_drop();\r
672         }\r
673 }\r
674 \r
675 \r
676 //--------------------------------------------------------------------------------------\r
677 // Plz\r
678 \r
679 function dis_exit()\r
680 {\r
681         return false;\r
682 }\r
683 \r
684 var s_nFrameCount = 0;\r
685 function dis_getmframe()\r
686 {\r
687         s_nFrameCount++;\r
688         return s_nFrameCount;\r
689 }\r
690 \r
691 function init_plz()\r
692 {\r
693         var a;\r
694 \r
695         // [NK 8/1/2014] Instead of writing the tables as assembly files,\r
696         // [NK 8/1/2014] just use them directly in C++.\r
697         {\r
698                 for(var a=0;a<1024*16;a++)\r
699                 {\r
700                         if(a<1024*8)\r
701                         {\r
702                                 lsini4_WriteWord(a, (Math.sin(a * DPII / 4096) * 55 + Math.sin(a * DPII / 4096 * 5) * 8 + Math.sin(a * DPII / 4096 * 15) * 2 + 64) * 8);\r
703                                 lsini16_WriteWord(a, (Math.sin(a * DPII / 4096) * 55 + Math.sin(a * DPII / 4096 * 4) * 5 + Math.sin(a * DPII / 4096 * 17) * 3 + 64) * 16);\r
704                         }\r
705                         psini_WriteByte(a, Math.sin(a * DPII / 4096) * 55 + Math.sin(a * DPII / 4096 * 6) * 5 + Math.sin(a * DPII / 4096 * 21) * 4 + 64);\r
706                 }\r
707 \r
708                 for(var a=1;a<=128;a++)\r
709                 {\r
710                         ptau_WriteByte(a, Math.cos(a * DPII / 128 + 3.1415926535) * 31 + 32);\r
711                 }\r
712         }\r
713 \r
714         cop_start=96*(682-400);\r
715         set_plzstart(60);\r
716         init_copper();\r
717         for(var a=0;a<256;a++) tw_setrgbpalette(a,63,63,63);\r
718 \r
719 //      RGB\r
720         var nPalOffset = ((0 * 768) + 3) * 2;\r
721         for(a=1;a<64;a++)\r
722         {\r
723                 pal_WriteWord(nPalOffset, ptau_ReadByte(a)); nPalOffset += 2;\r
724                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
725                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
726         }\r
727         for(a=0;a<64;a++)\r
728         {\r
729                 pal_WriteWord(nPalOffset, ptau_ReadByte(63 - a)); nPalOffset += 2;\r
730                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
731                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
732         }\r
733         for(a=0;a<64;a++)\r
734         {\r
735                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
736                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
737                 pal_WriteWord(nPalOffset, ptau_ReadByte(a)); nPalOffset += 2;\r
738         }\r
739         for(a=0;a<64;a++)\r
740         {\r
741                 pal_WriteWord(nPalOffset, ptau_ReadByte(a)); nPalOffset += 2;\r
742                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
743                 pal_WriteWord(nPalOffset, ptau_ReadByte(63 - a)); nPalOffset += 2;\r
744         }\r
745 \r
746 //      RB-black\r
747         nPalOffset = ((1 * 768) + 3) * 2;\r
748         for(a=1;a<64;a++)\r
749         {\r
750                 pal_WriteWord(nPalOffset, ptau_ReadByte(a)); nPalOffset += 2;\r
751                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
752                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
753         }\r
754         for(a=0;a<64;a++)\r
755         {\r
756                 pal_WriteWord(nPalOffset, ptau_ReadByte(63 - a)); nPalOffset += 2;\r
757                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
758                 pal_WriteWord(nPalOffset, ptau_ReadByte(a)); nPalOffset += 2;\r
759         }\r
760         for(a=0;a<64;a++)\r
761         {\r
762                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
763                 pal_WriteWord(nPalOffset, ptau_ReadByte(a)); nPalOffset += 2;\r
764                 pal_WriteWord(nPalOffset, ptau_ReadByte(63 - a)); nPalOffset += 2;\r
765         }\r
766         for(a=0;a<64;a++)\r
767         {\r
768                 pal_WriteWord(nPalOffset, ptau_ReadByte(a)); nPalOffset += 2;\r
769                 pal_WriteWord(nPalOffset, ptau_ReadByte(63)); nPalOffset += 2;\r
770                 pal_WriteWord(nPalOffset, ptau_ReadByte(a)); nPalOffset += 2;\r
771         }\r
772 \r
773 //      RB-white\r
774         nPalOffset = ((3 * 768) + 3) * 2;\r
775         for(a=1;a<64;a++)\r
776         {\r
777                 pal_WriteWord(nPalOffset, ptau_ReadByte(a)); nPalOffset += 2;\r
778                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
779                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
780         }\r
781         for(a=0;a<64;a++)\r
782         {\r
783                 pal_WriteWord(nPalOffset, ptau_ReadByte(63)); nPalOffset += 2;\r
784                 pal_WriteWord(nPalOffset, ptau_ReadByte(a)); nPalOffset += 2;\r
785                 pal_WriteWord(nPalOffset, ptau_ReadByte(a)); nPalOffset += 2;\r
786         }\r
787         for(a=0;a<64;a++)\r
788         {\r
789                 pal_WriteWord(nPalOffset, ptau_ReadByte(63-a)); nPalOffset += 2;\r
790                 pal_WriteWord(nPalOffset, ptau_ReadByte(63-a)); nPalOffset += 2;\r
791                 pal_WriteWord(nPalOffset, ptau_ReadByte(63)); nPalOffset += 2;\r
792         }\r
793         for(a=0;a<64;a++)\r
794         {\r
795                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
796                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)); nPalOffset += 2;\r
797                 pal_WriteWord(nPalOffset, ptau_ReadByte(63)); nPalOffset += 2;\r
798         }\r
799 \r
800 //      white\r
801         nPalOffset = ((2 * 768) + 3) * 2;\r
802         for(a=1;a<64;a++)\r
803         {\r
804                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)/2); nPalOffset += 2;\r
805                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)/2); nPalOffset += 2;\r
806                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)/2); nPalOffset += 2;\r
807         }\r
808         for(a=0;a<64;a++)\r
809         {\r
810                 pal_WriteWord(nPalOffset, ptau_ReadByte(a)/2); nPalOffset += 2;\r
811                 pal_WriteWord(nPalOffset, ptau_ReadByte(a)/2); nPalOffset += 2;\r
812                 pal_WriteWord(nPalOffset, ptau_ReadByte(a)/2); nPalOffset += 2;\r
813         }\r
814         for(a=0;a<64;a++)\r
815         {\r
816                 pal_WriteWord(nPalOffset, ptau_ReadByte(63-a)/2); nPalOffset += 2;\r
817                 pal_WriteWord(nPalOffset, ptau_ReadByte(63-a)/2); nPalOffset += 2;\r
818                 pal_WriteWord(nPalOffset, ptau_ReadByte(63-a)/2); nPalOffset += 2;\r
819         }\r
820         for(a=0;a<64;a++)\r
821         {\r
822                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)/2); nPalOffset += 2;\r
823                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)/2); nPalOffset += 2;\r
824                 pal_WriteWord(nPalOffset, ptau_ReadByte(0)/2); nPalOffset += 2;\r
825         }\r
826 \r
827 \r
828 //      white II\r
829         nPalOffset = ((4 * 768) + 3) * 2;\r
830         for(a=1;a<75;a++)\r
831         {\r
832                 pal_WriteWord(nPalOffset, ptau_ReadByte(63-a*64/75)); nPalOffset += 2;\r
833                 pal_WriteWord(nPalOffset, ptau_ReadByte(63-a*64/75)); nPalOffset += 2;\r
834                 pal_WriteWord(nPalOffset, ptau_ReadByte(63-a*64/75)); nPalOffset += 2;\r
835         }\r
836         for(a=0;a<106;a++)\r
837         {\r
838                 pal_WriteWord(nPalOffset, 0); nPalOffset += 2;\r
839                 pal_WriteWord(nPalOffset, 0); nPalOffset += 2;\r
840                 pal_WriteWord(nPalOffset, 0); nPalOffset += 2;\r
841         }\r
842         for(a=0;a<75;a++)\r
843         {\r
844                 pal_WriteWord(nPalOffset, ptau_ReadByte(a*64/75)*8/10); nPalOffset += 2;\r
845                 pal_WriteWord(nPalOffset, ptau_ReadByte(a*64/75)*9/10); nPalOffset += 2;\r
846                 pal_WriteWord(nPalOffset, ptau_ReadByte(a*64/75)); nPalOffset += 2;\r
847         }\r
848 \r
849         nPalOffset = 0;\r
850         for(var a=0;a<768;a++)\r
851         {\r
852                 var n = pal_ReadWord(nPalOffset);\r
853                 n -= 63;\r
854                 n *= 2;\r
855                 n &= 0xFFFF;\r
856                 pal_WriteWord(nPalOffset, n);\r
857                 nPalOffset += 2;\r
858         }\r
859 \r
860         for(var a=768;a<768*5;a++)\r
861         {\r
862                 var n = pal_ReadWord(nPalOffset);\r
863                 n *= 8;\r
864                 n &= 0xFFFF;\r
865                 pal_WriteWord(nPalOffset, n);\r
866                 nPalOffset += 2;\r
867         }\r
868 }\r
869 \r
870 function plz()\r
871 {\r
872         var y;\r
873 \r
874         if(dis_getmframe()>timetable[ttptr])\r
875         {\r
876                 fadepal_Clear();\r
877                 cop_drop=1;\r
878                 ttptr++;\r
879 \r
880                 if (ttptr == 4) {\r
881                         // [NK 18/1/2014] Loop back to the first plasma again.\r
882                         ttptr = 0;\r
883                         curpal = 0;\r
884                         s_nFrameCount = 0;\r
885                         fadepal_ClearToWhite();\r
886                         cop_drop = 1;\r
887                 }\r
888 \r
889                 cop_fadepal_SetSelectedPaletteIndex(curpal++);\r
890 \r
891                 il1=inittable[ttptr][0];\r
892                 il2=inittable[ttptr][1];\r
893                 il3=inittable[ttptr][2];\r
894                 il4=inittable[ttptr][3];\r
895                 ik1=inittable[ttptr][4];\r
896                 ik2=inittable[ttptr][5];\r
897                 ik3=inittable[ttptr][6];\r
898                 ik4=inittable[ttptr][7];\r
899         }\r
900 //      if (curpal == 5 && cop_drop > 64) {\r
901 //              return true;\r
902 //      }\r
903 \r
904         VGA_SelectBitPlanes02();\r
905 \r
906         setplzparas(k1,k2,k3,k4);\r
907         for(y=0;y<MAXY;y+=2)\r
908                 plzline(y,y*6);\r
909         setplzparas(l1,l2,l3,l4);\r
910         for(y=1;y<MAXY;y+=2)\r
911                 plzline(y,y*6);\r
912 \r
913         VGA_SelectBitPlanes13();\r
914 \r
915         setplzparas(k1,k2,k3,k4);\r
916         for(y=1;y<MAXY;y+=2)\r
917                 plzline(y,y*6);\r
918         setplzparas(l1,l2,l3,l4);\r
919         for(y=0;y<MAXY;y+=2)\r
920                 plzline(y,y*6);\r
921 \r
922         VGA_ShowFrameBuffer();\r
923 \r
924         return false;\r
925 //      cop_drop=0;\r
926 //      set_plzstart(500);\r
927 //      cop_plz=0;\r
928 }\r
929 \r
930 \r
931 //--------------------------------------------------------------------------------------\r
932 // Main\r
933 \r
934 function tmain()\r
935 {\r
936         // Create arrays.\r
937         inittable[0] = [1000,2000,3000,4000,3500,2300,3900,3670];\r
938         inittable[1] = [1000,2000,4000,4000,1500,2300,3900,1670];\r
939         inittable[2] = [3500,1000,3000,1000,3500,3300,2900,2670];\r
940         inittable[3] = [1000,2000,3000,4000,3500,2300,3900,3670];\r
941         inittable[4] = [1000,2000,3000,4000,3500,2300,3900,3670];\r
942         inittable[5] = [1000,2000,3000,4000,3500,2300,3900,3670];\r
943 \r
944         init_copper();\r
945         init_plz();\r
946         cop_drop = 128;\r
947         cop_fadepal_SetSelectedPaletteIndex(curpal++);\r
948 }\r
949 \r
950 \r
951 //--------------------------------------------------------------------------------------\r
952 // HTML5 specific code\r
953 \r
954 window.onload = function () {\r
955         document.getElementsByTagName("body")[0].className = "js";\r
956 \r
957         start();\r
958 };\r
959 \r
960 var canvas = null;\r
961 var context = null;\r
962 var fps = null;\r
963 var tscale = 0.02;\r
964 var lastTick = 0;\r
965 var targetFps = 1;\r
966 var image;\r
967 var canvasId = "canvas";\r
968 var fpsId = "fps";\r
969 \r
970 function init() {\r
971         canvas = canvasId ? document.getElementById(canvasId) : null;\r
972         fps = fpsId ? document.getElementById(fpsId) : null;\r
973 \r
974         if (canvas && canvas.getContext) {\r
975                 //              canvas.width = width = window.innerWidth;\r
976                 //              canvas.height = height = window.innerHeight;\r
977                 canvas.width = 320;\r
978                 canvas.height = 400;\r
979 \r
980                 context = canvas.getContext("2d");\r
981 \r
982                 if (context.createImageData) {\r
983                         image = context.createImageData(canvas.width, canvas.height);\r
984                 } else if (context.getImageData) {\r
985                         image = context.getImageData(0, 0, canvas.width, canvas.height);\r
986                 } else {\r
987                         // it's Opera\r
988                         image = { 'width': canvas.width, 'height': canvas.height,\r
989                                 'data': new Array(canvas.width * canvas.height * 4)\r
990                         }\r
991                 }\r
992 \r
993                 for (i = 0; i < image.data.length; i++) {\r
994                         image.data[i] = 255;\r
995                 }\r
996                 return true;\r
997         } else {\r
998                 return false;\r
999         }\r
1000 }\r
1001 \r
1002 function draw() {\r
1003 \r
1004         // Clear to black.\r
1005         length = 320 * 400;\r
1006         var p = 0;\r
1007         for (var i = 0; i < length; i++) {\r
1008                 image.data[p] = 0;\r
1009                 p++;\r
1010                 image.data[p] = 0;\r
1011                 p++;\r
1012                 image.data[p] = 0;\r
1013                 p++;\r
1014                 image.data[p] = 0xFF;\r
1015                 p++;\r
1016         }\r
1017 \r
1018         IsComplete = plz();\r
1019 \r
1020         if (!image) {\r
1021                 return;\r
1022         }\r
1023 \r
1024         var x = 0;\r
1025         var y = 0;\r
1026 //      var x = (window.innerWidth - 320) / 2;\r
1027 //      var y = (window.innerHeight - 400) / 2;\r
1028 \r
1029         context.putImageData(image, x, y);\r
1030 }\r
1031 \r
1032 function tick() {\r
1033         var start, elapsed, sleep, target;\r
1034         start = new Date().getTime();\r
1035 \r
1036         // check if the canvas has been resized\r
1037 //      if ((canvas.clientWidth / 8) != width ||\r
1038 //        (canvas.clientHeight / 8) != height) {\r
1039 //              init();\r
1040 //      }\r
1041 \r
1042         if (!IsComplete) {\r
1043                 draw();\r
1044         }\r
1045 \r
1046         // calculate stable FPS \r
1047         elapsed = new Date().getTime() - start;\r
1048 \r
1049         target = 1000 / 60;\r
1050 \r
1051         // calculate sleep and schedule next tick\r
1052         sleep = target - elapsed;\r
1053         if (sleep < 1) {\r
1054                 sleep = 1;\r
1055         } else if (sleep > 1000) {\r
1056                 sleep = 1000;\r
1057         }\r
1058 \r
1059         lastTick = start;\r
1060         setTimeout(tick, sleep);\r
1061 }\r
1062 \r
1063 function start() {\r
1064         lastTick = new Date().getTime();\r
1065 \r
1066         tmain();\r
1067 \r
1068         if (init()) tick();\r
1069 }\r