188 lines
5.9 KiB
Go
188 lines
5.9 KiB
Go
package main
|
|
|
|
import "fmt"
|
|
|
|
/*
|
|
* This file is part of CD+Graphics Magic.
|
|
*
|
|
* CD+Graphics Magic is free software: you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation, either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* CD+Graphics Magic is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with CD+Graphics Magic. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* This class instantiates an HTML5/Canvas CD+Graphics decoder object.
|
|
*
|
|
* This is the "low resource" version, and should be very close
|
|
* to as fast as possible with JavaScript.
|
|
*
|
|
* The difference between the "low resource" and normal version
|
|
* is that this one packs each 6 pixel font line in to one
|
|
* array value, unrolling some loops and minimizing array lookups.
|
|
*
|
|
* The only concession made is lack of H/V "offset" support used
|
|
* for smooth scrolling.
|
|
* Block based scrolls *are* still supported, however, so the basic
|
|
* intent of the graphics is presented, but less than ideally.
|
|
*
|
|
* It is recommended for CPU constrained (eg. mobile or embedded) devices.
|
|
*
|
|
*/
|
|
|
|
// Useful enums for CD+Graphics...
|
|
|
|
const (
|
|
VRAM_SIZE = 300 * 216 // Total linear size of VRAM, in pixels.
|
|
VRAM_WIDTH = 300 // Width (or pitch) of VRAM, in pixels.
|
|
VRAM_HEIGHT = 216 // Height of VRAM, in pixels.
|
|
VISIBLE_SIZE = 288 * 192 // Total linear size of visible screen, in pixels.
|
|
VISIBLE_WIDTH = 288 // Width (or pitch) of visible screen, in pixels.
|
|
VISIBLE_HEIGHT = 192 // Height of visible screen, in pixels.
|
|
FONT_WIDTH = 6 // Width of one "font" (or block).
|
|
FONT_HEIGHT = 12 // Height of one "font" (or block).
|
|
NUM_X_FONTS = 50 // Number of horizontal fonts contained in VRAM.
|
|
NUM_Y_FONTS = 18 // Number of vertical fonts contained in VRAM.
|
|
PALETTE_ENTRIES = 16 // Number of CLUT palette entries.
|
|
TV_GRAPHICS = 0x09 // 50x18 (48x16) 16 color TV graphics mode.
|
|
MEMORY_PRESET = 0x01 // Set all VRAM to palette index.
|
|
BORDER_PRESET = 0x02 // Set border to palette index.
|
|
LOAD_CLUT_LO = 0x1E // Load Color Look Up Table index 0 through 7.
|
|
LOAD_CLUT_HI = 0x1F // Load Color Look Up Table index 8 through 15.
|
|
COPY_FONT = 0x06 // Copy 12x6 pixel font to screen.
|
|
XOR_FONT = 0x26 // XOR 12x6 pixel font with existing VRAM values.
|
|
SCROLL_PRESET = 0x14 // Update scroll offset, copying if 0x20 or 0x10.
|
|
SCROLL_COPY = 0x18 // Update scroll offset, setting color if 0x20 or 0x10.
|
|
)
|
|
|
|
var (
|
|
internal_palette = make([]byte, PALETTE_ENTRIES)
|
|
internal_vram = make([]byte, NUM_X_FONTS*VRAM_HEIGHT)
|
|
internal_dirty_blocks = make([]byte, 900)
|
|
|
|
internal_border_index = 0x00 // The current border palette index.
|
|
internal_current_pack = 0x00 //
|
|
|
|
internal_border_dirty = false
|
|
internal_screen_dirty = false
|
|
)
|
|
|
|
func main() {
|
|
fmt.Println("Compiles baby!")
|
|
}
|
|
|
|
func resetCDGState() {
|
|
internal_current_pack = 0x00
|
|
internal_border_index = 0x00
|
|
clearPalette()
|
|
clearVRAM(0x00)
|
|
clearDirtyBlocks()
|
|
}
|
|
|
|
func clearPalette() {
|
|
for idx := 0; idx < PALETTE_ENTRIES; idx++ {
|
|
internal_palette[idx] = 0x00
|
|
}
|
|
}
|
|
|
|
func get_current_pack() byte {
|
|
//casting: must test!!!
|
|
return byte(internal_current_pack)
|
|
}
|
|
|
|
/* Possibly not needed!
|
|
func set_dirtyrect(requested_value) {
|
|
internal_usedirtyrect = requested_value
|
|
}
|
|
*/
|
|
|
|
func redrawCanvas() {
|
|
|
|
if internal_border_dirty || internal_screen_dirty {
|
|
// render_screen_to_rgb()
|
|
// internal_screen_dirty = 0
|
|
// clear_dirty_blocks()
|
|
// internal_rgba_context.putImageData(internal_rgba_imagedata, 0, 0)
|
|
} else {
|
|
var local_context = internal_rgba_context
|
|
var local_rgba_imagedata = internal_rgba_imagedata
|
|
|
|
update_needed := false
|
|
var blk = 0x00
|
|
|
|
//NOTE: test the post-increment (Go does not have pre, so had to change it)
|
|
|
|
for y_blk := 1; y_blk <= 16; y_blk++ {
|
|
|
|
blk = y_blk*NUM_X_FONTS + 1
|
|
|
|
for x_blk := 1; x_blk <= 48; x_blk++ {
|
|
|
|
if internal_dirty_blocks[blk] {
|
|
|
|
render_block_to_rgb(x_blk, y_blk)
|
|
|
|
if internal_usedirtyrect == 0x01 {
|
|
local_context.putImageData(local_rgba_imagedata, 0, 0,
|
|
(x_blk-1)*FONT_WIDTH,
|
|
(y_blk-1)*FONT_HEIGHT,
|
|
FONT_WIDTH,
|
|
FONT_HEIGHT)
|
|
} else {
|
|
update_needed = 0x01
|
|
}
|
|
|
|
internal_dirty_blocks[blk] = 0x00
|
|
}
|
|
//Note: test the post-increment
|
|
blk++
|
|
}
|
|
}
|
|
// Update the whole screen for browsers where dirty rect isn't supported.
|
|
// Since this can't be detected(???) in any way, it has to be User Agent selected, or an actual user option.
|
|
// TODO: See if a dirty rect-based partial update of known pixel values combined with a getImageData
|
|
// call could be used to determine if it works correctly *without* evil browser sniffing.
|
|
if update_needed {
|
|
//local_context.putImageData(local_rgba_imagedata, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
func clearVRAM(colorIndex byte) {
|
|
|
|
packed_line_value := fill_line_with_palette_index(colorIndex)
|
|
|
|
for pxl := 0; pxl < len(internal_vram); pxl++ {
|
|
internal_vram[pxl] = packed_line_value
|
|
}
|
|
|
|
internal_screen_dirty = true
|
|
}
|
|
|
|
func clearDirtyBlocks() {
|
|
for blk := 0; blk < 900; blk++ {
|
|
internal_dirty_blocks[blk] = 0x00
|
|
}
|
|
}
|
|
|
|
func fill_line_with_palette_index(requested_index byte) byte {
|
|
|
|
adjusted_value := requested_index // Pixel 0
|
|
adjusted_value |= (requested_index << 004) // Pixel 1
|
|
adjusted_value |= (requested_index << 010) // Pixel 2
|
|
adjusted_value |= (requested_index << 014) // Pixel 3
|
|
adjusted_value |= (requested_index << 020) // Pixel 4
|
|
adjusted_value |= (requested_index << 024) // Pixel 5
|
|
|
|
return adjusted_value
|
|
}
|