Got the basics of sprites working
This commit is contained in:
@@ -10,7 +10,7 @@ HARE_SOURCES != find . -name '*.ha'
|
|||||||
build: build/meadow
|
build: build/meadow
|
||||||
|
|
||||||
run: build
|
run: build
|
||||||
build/meadow screentest.rom
|
build/meadow monospace.rom
|
||||||
|
|
||||||
build/meadow: $(HARE_SOURCES)
|
build/meadow: $(HARE_SOURCES)
|
||||||
hare build $(LIBS) -o build/meadow src/
|
hare build $(LIBS) -o build/meadow src/
|
||||||
|
|||||||
+47
-47
@@ -17,13 +17,13 @@ export fn main() void = {
|
|||||||
|
|
||||||
const win = sdl3::CreateWindow(
|
const win = sdl3::CreateWindow(
|
||||||
c::nulstr("Meadow\0"),
|
c::nulstr("Meadow\0"),
|
||||||
WIDTH, HEIGHT, 0)!;
|
WIDTH, HEIGHT, sdl3::WindowFlags::RESIZABLE)!;
|
||||||
defer sdl3::DestroyWindow(win);
|
defer sdl3::DestroyWindow(win);
|
||||||
|
|
||||||
const render = sdl3::CreateRenderer(win, null)!;
|
const render = sdl3::CreateRenderer(win, null)!;
|
||||||
defer sdl3::DestroyRenderer(render);
|
defer sdl3::DestroyRenderer(render);
|
||||||
sdl3::SetRenderDrawColor(render, 0, 0, 128, 255)!;
|
sdl3::SetRenderDrawColor(render, 0, 0, 128, 255)!;
|
||||||
|
sdl3::SetRenderVSync(render,1)!;
|
||||||
// const img = image::LoadTexture(render, c::nulstr("./assets/mascot.jpg\0"))!;
|
// const img = image::LoadTexture(render, c::nulstr("./assets/mascot.jpg\0"))!;
|
||||||
// defer sdl3::DestroyTexture(img);
|
// defer sdl3::DestroyTexture(img);
|
||||||
|
|
||||||
@@ -58,8 +58,12 @@ export fn main() void = {
|
|||||||
let path = os::args[1];
|
let path = os::args[1];
|
||||||
let state: *uxn::uxn = uxn::uxn_init(path)!;
|
let state: *uxn::uxn = uxn::uxn_init(path)!;
|
||||||
uxn::uxn_reset(state);
|
uxn::uxn_reset(state);
|
||||||
|
let next_refresh: u64 = 0;
|
||||||
|
const perf_freq: u64 = sdl3::GetPerformanceFrequency();
|
||||||
|
const frame_interval = perf_freq / 60;
|
||||||
|
const ms_interval = perf_freq / 1000;
|
||||||
for (run) {
|
for (run) {
|
||||||
//UXN stuff
|
const now: u64 = sdl3::GetPerformanceCounter();
|
||||||
if(state.running){
|
if(state.running){
|
||||||
// fmt::printf("Next Step!\n")!;
|
// fmt::printf("Next Step!\n")!;
|
||||||
uxn::uxn_step(state)!;
|
uxn::uxn_step(state)!;
|
||||||
@@ -115,12 +119,18 @@ export fn main() void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(now >= next_refresh){
|
||||||
|
next_refresh = now + frame_interval;
|
||||||
|
|
||||||
|
if(state.screen_vector != 0){
|
||||||
|
uxn::uxn_eval(state.screen_vector, state)!;
|
||||||
|
};
|
||||||
|
};
|
||||||
if(state.screen_size_changed){
|
if(state.screen_size_changed){
|
||||||
let dims = uxn::get_window_size(state);
|
let dims = uxn::get_window_size(state);
|
||||||
// fmt::printfln("Setting window to width: {:x} height: {:x}", dims.width, dims.height)!;
|
// fmt::printfln("Setting window to width: {:x} height: {:x}", dims.width, dims.height)!;
|
||||||
if((dims.width != 0) && (dims.height !=0)){
|
if((dims.width != 0) && (dims.height !=0)){
|
||||||
//TODO, check current dims
|
|
||||||
//
|
|
||||||
sdl3::DestroyTexture(meadow_texture);
|
sdl3::DestroyTexture(meadow_texture);
|
||||||
let w: int = dims.width: int;
|
let w: int = dims.width: int;
|
||||||
let h: int = dims.height: int;
|
let h: int = dims.height: int;
|
||||||
@@ -142,34 +152,23 @@ export fn main() void = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if(state.screen_update){
|
if(state.screen_update){
|
||||||
let pcount = 0;
|
|
||||||
const dims = uxn::get_window_size(state);
|
const dims = uxn::get_window_size(state);
|
||||||
for(let y: u16 = 0; y <= dims.height: u16; y+=1 ){
|
for(let y: u16 = 0; y <= dims.height: u16; y+=1 ){
|
||||||
for(let x: u16 = 0; x <= dims.width: u16; x+=1 ){
|
for(let x: u16 = 0; x <= dims.width: u16; x+=1 ){
|
||||||
let colshort: u16 = uxn::get_color(x,y,state);
|
let colshort: u16 = uxn::get_color(x,y,state);
|
||||||
//take 16-bit color and transform to 32-bit number
|
|
||||||
//XRGB -> XXRXGXBX
|
|
||||||
// const r = (colshort & 0x0F00): u32 << (3*4);
|
|
||||||
// const g = (colshort & 0x00F0): u32 << (2*4);
|
|
||||||
// const b = (colshort & 0x000F): u32 << (1*4);
|
|
||||||
// const color: u32 = r | g | b;
|
|
||||||
// const data = pixeldata: *[*]u32; //
|
|
||||||
// if(colshort !=0x0fff){
|
|
||||||
// fmt::printfln("Pixel x: {:x} y: {:x} color: {:x}", x, y, colshort)!;
|
|
||||||
// };
|
|
||||||
// fmt::printfln("Pixel x: {} y: {} color: {:x} pcount: {:x}", x, y, colshort, pcount)!;
|
// fmt::printfln("Pixel x: {} y: {} color: {:x} pcount: {:x}", x, y, colshort, pcount)!;
|
||||||
if(y == 0 && x < 64) colshort = 0;
|
|
||||||
const index: u32 = y: u32 * dims.width: u32 + x: u32;
|
const index: u32 = y: u32 * dims.width: u32 + x: u32;
|
||||||
// if(index < 10) fmt::printfln("pcount: {} index: {} x: {} y: {}", pcount, index, x, y)!;
|
// if(index < 10) fmt::printfln("pcount: {} index: {} x: {} y: {}", pcount, index, x, y)!;
|
||||||
pixeldata[index] = colshort;
|
pixeldata[index] = colshort;
|
||||||
pcount +=1;
|
|
||||||
};
|
};
|
||||||
// pixeldata[pcount] = 0;
|
|
||||||
// pcount += 4096;
|
|
||||||
};
|
};
|
||||||
const pitch: int = dims.width: int * 2;
|
const pitch: int = dims.width: int * 2;
|
||||||
fmt::printfln("Pitch is {}", pitch)!;
|
// fmt::printfln("Pitch is {}", pitch)!;
|
||||||
if(pitch > 0) sdl3::UpdateTexture(meadow_texture, null, pixeldata, pitch)!;
|
if(pitch > 0) sdl3::UpdateTexture(meadow_texture, null, pixeldata, pitch)!;
|
||||||
|
sdl3::RenderClear(render)!;
|
||||||
|
sdl3::RenderTexture(render, meadow_texture, null, null)!;
|
||||||
|
|
||||||
|
sdl3::RenderPresent(render)!;
|
||||||
state.screen_update = false;
|
state.screen_update = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -178,38 +177,39 @@ export fn main() void = {
|
|||||||
for (sdl3::PollEvent(&ev)) {
|
for (sdl3::PollEvent(&ev)) {
|
||||||
if (ev.event_type == sdl3::EventType::QUIT) {
|
if (ev.event_type == sdl3::EventType::QUIT) {
|
||||||
run = false;
|
run = false;
|
||||||
|
}else if(ev.event_type == sdl3::EventType::WINDOW_RESIZED){
|
||||||
|
let dims = uxn::get_window_size(state);
|
||||||
|
let w = ev.window.data1;
|
||||||
|
let h = ev.window.data2;
|
||||||
|
if((dims.width != w: u16) || (dims.height != h: u16)){
|
||||||
|
// fmt::println("Dimensions not allowed!")!;
|
||||||
|
//TODO handle this maybe
|
||||||
|
sdl3::DestroyTexture(meadow_texture);
|
||||||
|
let old_w: int = dims.width: int;
|
||||||
|
let old_h: int = dims.height: int;
|
||||||
|
|
||||||
|
fmt::printfln("Setting window to width: {} height: {}", w, h)!;
|
||||||
|
sdl3::SetWindowSize(win,w,h)!;
|
||||||
|
|
||||||
|
meadow_texture = sdl3::CreateTexture(render,
|
||||||
|
sdl3::PixelFormat::XRGB4444,
|
||||||
|
sdl3::TextureAccess::STATIC,
|
||||||
|
w,
|
||||||
|
h)!;
|
||||||
|
|
||||||
|
state.screen_update = true;
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
sdl3::RenderClear(render)!;
|
|
||||||
|
|
||||||
|
// sdl3::RenderClear(render)!;
|
||||||
|
// sdl3::RenderTexture(render, meadow_texture, null, null)!;
|
||||||
|
|
||||||
sdl3::RenderTexture(render, meadow_texture, null, null)!;
|
// sdl3::RenderPresent(render)!;
|
||||||
|
// sdl3::Delay(1000 / 60);
|
||||||
|
|
||||||
// sdl3::RenderTexture(render, img, null, &sdl3::FRect {
|
|
||||||
// x = x: f32,
|
|
||||||
// y = y: f32,
|
|
||||||
// w = w: f32,
|
|
||||||
// h = h: f32,
|
|
||||||
// })!;
|
|
||||||
|
|
||||||
sdl3::RenderPresent(render)!;
|
|
||||||
sdl3::Delay(1000 / 60);
|
|
||||||
|
|
||||||
// x += xd;
|
|
||||||
// y += yd;
|
|
||||||
// if (x + w >= WIDTH) {
|
|
||||||
// xd = -1;
|
|
||||||
// };
|
|
||||||
// if (x <= 0) {
|
|
||||||
// xd = 1;
|
|
||||||
// };
|
|
||||||
// if (y + h >= HEIGHT) {
|
|
||||||
// yd = -1;
|
|
||||||
// };
|
|
||||||
// if (y <= 0) {
|
|
||||||
// yd = 1;
|
|
||||||
// };
|
|
||||||
|
|
||||||
sdl3::get_error()!;
|
sdl3::get_error()!;
|
||||||
};
|
};
|
||||||
|
|||||||
+116
-4
@@ -29,6 +29,7 @@ export type uxn = struct {
|
|||||||
//TODO find a way to use these below
|
//TODO find a way to use these below
|
||||||
export def MAXWIDTH = 4096;
|
export def MAXWIDTH = 4096;
|
||||||
export def MAXHEIGHT = 2160;
|
export def MAXHEIGHT = 2160;
|
||||||
|
export def SCREENRATE = 60;
|
||||||
//Screen consists of two layers of 2-bit pixels
|
//Screen consists of two layers of 2-bit pixels
|
||||||
export type uxn_screen = ([MAXWIDTH][MAXHEIGHT]u8, [MAXWIDTH][MAXHEIGHT]u8);
|
export type uxn_screen = ([MAXWIDTH][MAXHEIGHT]u8, [MAXWIDTH][MAXHEIGHT]u8);
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ fn emu_deo(port: u8, value: u8, state: *uxn) void = {
|
|||||||
case 0x2e =>
|
case 0x2e =>
|
||||||
draw_pixel(value,state);
|
draw_pixel(value,state);
|
||||||
case 0x2f =>
|
case 0x2f =>
|
||||||
yield;
|
draw_sprite(value,state);
|
||||||
case =>
|
case =>
|
||||||
if( port == 0x22 ||
|
if( port == 0x22 ||
|
||||||
port == 0x23 ||
|
port == 0x23 ||
|
||||||
@@ -133,13 +134,31 @@ fn draw_pixel(value: u8, state: *uxn) void = {
|
|||||||
|
|
||||||
if(!fill){
|
if(!fill){
|
||||||
// fmt::printfln("Pixel at x: {:x} y: {:x} color: {:x}", x, y, color)!;
|
// fmt::printfln("Pixel at x: {:x} y: {:x} color: {:x}", x, y, color)!;
|
||||||
|
const auto = state.dev[0x26];
|
||||||
|
let count = ((auto & 0xf0) >> 4): i8;
|
||||||
|
const auto_x = (auto & 0b00000001) != 0;
|
||||||
|
const auto_y = (auto & 0b00000010) != 0;
|
||||||
|
const auto_a = (auto & 0b00000100) != 0;
|
||||||
if(!layer1){
|
if(!layer1){
|
||||||
state.screen.0[x][y] = color;
|
state.screen.0[x][y] = color;
|
||||||
} else {
|
} else {
|
||||||
state.screen.1[x][y] = color;
|
state.screen.1[x][y] = color;
|
||||||
};
|
};
|
||||||
|
if(auto_x) {
|
||||||
|
const new_x = x + 1;
|
||||||
|
state.dev[0x28] = (new_x >> 8): u8;
|
||||||
|
state.dev[0x29] = (new_x): u8;
|
||||||
|
|
||||||
|
};
|
||||||
|
if(auto_y) {
|
||||||
|
const new_y = y + 1;
|
||||||
|
state.dev[0x2a] = (new_y >> 8): u8;
|
||||||
|
state.dev[0x2b] = (new_y): u8;
|
||||||
|
|
||||||
|
};
|
||||||
}else{
|
}else{
|
||||||
fmt::println("Doing Fill")!;
|
//TODO see if auto still happens with fill
|
||||||
|
// fmt::println("Doing Fill")!;
|
||||||
const dims = get_window_size(state);
|
const dims = get_window_size(state);
|
||||||
const startx: u16 = if(flipx) {yield 0; }else{ yield x; };
|
const startx: u16 = if(flipx) {yield 0; }else{ yield x; };
|
||||||
const starty: u16 = if(flipy) {yield 0; }else{ yield y; };
|
const starty: u16 = if(flipy) {yield 0; }else{ yield y; };
|
||||||
@@ -162,6 +181,93 @@ fn draw_pixel(value: u8, state: *uxn) void = {
|
|||||||
state.screen_update = true;
|
state.screen_update = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn draw_sprite(value: u8, state: *uxn) void = {
|
||||||
|
//TODO handle fill
|
||||||
|
const colors = value & 0b00001111;
|
||||||
|
const auto = state.dev[0x26];
|
||||||
|
let count = ((auto & 0xf0) >> 4): i8;
|
||||||
|
const auto_x = (auto & 0b00000001) != 0;
|
||||||
|
const auto_y = (auto & 0b00000010) != 0;
|
||||||
|
const auto_a = (auto & 0b00000100) != 0;
|
||||||
|
const bpp2: bool = (value & 0b10000000) != 0;
|
||||||
|
const layer1: bool = (value & 0b01000000) != 0;
|
||||||
|
const flipy: bool = (value & 0b00100000) != 0;
|
||||||
|
const flipx: bool = (value & 0b00010000) != 0;
|
||||||
|
|
||||||
|
for(let i = 0; i <= count; i+=1){
|
||||||
|
const addr = short_from_bytes(state.dev[0x2c],state.dev[0x2d]);
|
||||||
|
const x = short_from_bytes(state.dev[0x28],state.dev[0x29]);
|
||||||
|
const y = short_from_bytes(state.dev[0x2a],state.dev[0x2b]);
|
||||||
|
copy_sprite_to_screen(bpp2,colors,x,y,addr,flipx,flipy,layer1,state);
|
||||||
|
|
||||||
|
if(auto_x) {
|
||||||
|
const new_x = x + 8;
|
||||||
|
state.dev[0x28] = (new_x >> 8): u8;
|
||||||
|
state.dev[0x29] = (new_x): u8;
|
||||||
|
|
||||||
|
};
|
||||||
|
if(auto_y) {
|
||||||
|
const new_y = y + 8;
|
||||||
|
state.dev[0x2a] = (new_y >> 8): u8;
|
||||||
|
state.dev[0x2b] = (new_y): u8;
|
||||||
|
|
||||||
|
};
|
||||||
|
if(auto_a){
|
||||||
|
const new_addr = if(bpp2) { yield addr + 16; } else { yield addr + 8; };
|
||||||
|
|
||||||
|
state.dev[0x2c] = (new_addr >> 8): u8;
|
||||||
|
state.dev[0x2d] = (new_addr): u8;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
state.screen_update = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
fn copy_sprite_to_screen(bpp2: bool, colors: u8, x: u16, y: u16, addr: u16, flipx: bool, flipy: bool, layer1: bool, state: *uxn) void = {
|
||||||
|
const bytes_per_sprite = if(bpp2) {yield 16;} else {yield 8;};
|
||||||
|
let xoff: u16 = 0;
|
||||||
|
let yoff: u16 = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fmt::printfln("Drawing Sprite to x: {} y: {}", x, y)!;
|
||||||
|
for(let i = 0; i < bytes_per_sprite; i+=1){
|
||||||
|
let data: u8 = state.ram[addr + i: u16];
|
||||||
|
const pixels: []u8 = if(bpp2){
|
||||||
|
yield [
|
||||||
|
(data & 0b11000000) >> 6,
|
||||||
|
(data & 0b00110000) >> 4,
|
||||||
|
(data & 0b00001100) >> 2,
|
||||||
|
(data & 0b00000011) >> 0 ];
|
||||||
|
} else {
|
||||||
|
yield [
|
||||||
|
(data & 0b10000000) >> 7,
|
||||||
|
(data & 0b01000000) >> 6,
|
||||||
|
(data & 0b00100000) >> 5,
|
||||||
|
(data & 0b00010000) >> 4,
|
||||||
|
(data & 0b00001000) >> 3,
|
||||||
|
(data & 0b00000100) >> 2,
|
||||||
|
(data & 0b00000010) >> 1,
|
||||||
|
(data & 0b00000001) >> 0 ];
|
||||||
|
};
|
||||||
|
|
||||||
|
for(let p .. pixels){
|
||||||
|
const color = p; //TODO handle right;
|
||||||
|
fmt::printfln("Drawing 2bpp: {} Sprite Pixel to x: {} y: {} color: {}", bpp2, x+xoff, y+yoff, p)!;
|
||||||
|
if(layer1) { state.screen.1[x+xoff][y+yoff] = p; }
|
||||||
|
else {state.screen.0[x+xoff][y+yoff] = p; };
|
||||||
|
xoff += 1;
|
||||||
|
if(xoff >= 8){
|
||||||
|
xoff = 0;
|
||||||
|
yoff += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
export fn get_color(x: u16, y: u16, state: *uxn) u16 = {
|
export fn get_color(x: u16, y: u16, state: *uxn) u16 = {
|
||||||
// check layer 1
|
// check layer 1
|
||||||
let color = state.screen.1[x][y] & 0b00000011;
|
let color = state.screen.1[x][y] & 0b00000011;
|
||||||
@@ -404,7 +510,7 @@ fn pop_or_get(inst: normal_op, off: u8, state: *uxn) (u8 | u16) = {
|
|||||||
yield get_stack_val(inst.ret,inst.short, off,state);
|
yield get_stack_val(inst.ret,inst.short, off,state);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
fn uxn_eval(new_pc: u16, state: *uxn) (done | error ) = {
|
export fn uxn_eval(new_pc: u16, state: *uxn) (done | error ) = {
|
||||||
// let a: u16 = 0, b: u16 = 0, c: u16 = 0, x: [2]u16 = [0...], y: [2]u16 = [0...], z: [2]u16 = [0...];
|
// let a: u16 = 0, b: u16 = 0, c: u16 = 0, x: [2]u16 = [0...], y: [2]u16 = [0...], z: [2]u16 = [0...];
|
||||||
state.pc = new_pc;
|
state.pc = new_pc;
|
||||||
state.running = true;
|
state.running = true;
|
||||||
@@ -833,6 +939,12 @@ export fn uxn_init(path: str) ( *uxn | error ) = {
|
|||||||
};
|
};
|
||||||
io::close(romfile)!; //TODO, isn't there some kind of oversized roms?
|
io::close(romfile)!; //TODO, isn't there some kind of oversized roms?
|
||||||
|
|
||||||
|
//Initialize default size
|
||||||
|
state.dev[0x22] = 0x02;
|
||||||
|
state.dev[0x23] = 0x80;
|
||||||
|
state.dev[0x24] = 0x01;
|
||||||
|
state.dev[0x25] = 0xe0;
|
||||||
|
|
||||||
//Initialize default colors TODO look for .theme files
|
//Initialize default colors TODO look for .theme files
|
||||||
state.dev[0x08] = 0xf0;
|
state.dev[0x08] = 0xf0;
|
||||||
state.dev[0x09] = 0x7f;
|
state.dev[0x09] = 0x7f;
|
||||||
@@ -844,8 +956,8 @@ export fn uxn_init(path: str) ( *uxn | error ) = {
|
|||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
export fn uxn_reset(state: *uxn) void = {
|
export fn uxn_reset(state: *uxn) void = {
|
||||||
state.pc = reset_vector;
|
|
||||||
state.running = true;
|
state.running = true;
|
||||||
|
uxn_eval(reset_vector,state)!;
|
||||||
};
|
};
|
||||||
export fn uxnrun() void = {
|
export fn uxnrun() void = {
|
||||||
if(len(os::args) < 2){
|
if(len(os::args) < 2){
|
||||||
|
|||||||
Reference in New Issue
Block a user