nuclear@0: #include nuclear@11: #include nuclear@6: #include nuclear@0: #include nuclear@11: #include nuclear@0: #include "gfx.h" nuclear@0: #include "copper.h" nuclear@0: #include "hwregs.h" nuclear@0: #include "logger.h" nuclear@4: #include "image.h" nuclear@0: nuclear@0: static int scr_width, scr_height; nuclear@0: static int fb_width, fb_height; nuclear@0: static int num_bitplanes; nuclear@11: static unsigned int init_flags; nuclear@11: /* updated by vblank_intr to indicate the current field in interlaced mode */ nuclear@11: static unsigned short scr_field; nuclear@11: static uint32_t *coplist_bplptr[6]; nuclear@11: nuclear@0: static uint16_t prev_intena, prev_intreq, prev_adkcon, prev_dmacon; nuclear@0: nuclear@0: static unsigned char *framebuf; nuclear@0: static unsigned long fbsize; nuclear@0: static int own_framebuf; nuclear@0: nuclear@11: static unsigned int short_fields, long_fields; nuclear@11: nuclear@11: static struct Interrupt *vbint; nuclear@11: nuclear@11: static __amigainterrupt void vblank_intr(); nuclear@11: nuclear@0: int gfx_init(int nbpl, unsigned int flags) nuclear@0: { nuclear@0: uint16_t bplcon0; nuclear@0: nuclear@11: init_flags = flags; nuclear@0: num_bitplanes = nbpl; nuclear@0: scr_width = fb_width = (flags & GFX_HIRES) ? 640 : 320; nuclear@0: scr_height = fb_height = (flags & GFX_ILACE) ? 512 : 256; nuclear@0: nuclear@0: Forbid(); nuclear@0: nuclear@0: prev_dmacon = REG_DMACONR; nuclear@0: REG_DMACON = CLRBITS(DMA_ALL); nuclear@0: nuclear@0: prev_intena = REG_INTENAR; nuclear@0: prev_intreq = REG_INTREQR; nuclear@0: prev_adkcon = REG_ADKCONR; nuclear@0: nuclear@6: if(init_copper(1400, 0) == -1) { nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@11: /* setup vblank interrupt handler */ nuclear@11: if(!(vbint = malloc(sizeof *vbint))) { nuclear@11: gfx_shutdown(); nuclear@11: return -1; nuclear@11: } nuclear@11: vbint->is_Node.ln_Type = NT_INTERRUPT; nuclear@11: vbint->is_Node.ln_Pri = -60; nuclear@11: vbint->is_Node.ln_Name = "imgv_vblank_intr"; nuclear@11: vbint->is_Data = 0; nuclear@11: vbint->is_Code = vblank_intr; nuclear@11: nuclear@11: AddIntServer(INTR_VERTB, vbint); nuclear@11: nuclear@0: if(!gfx_set_framebuffer(0, scr_width, scr_height)) { nuclear@0: gfx_shutdown(); nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: bplcon0 = BPLCON0_COUNT(nbpl) | BPLCON0_COLOR; nuclear@0: if(flags & GFX_HIRES) bplcon0 |= BPLCON0_HIRES; nuclear@0: if(flags & GFX_ILACE) bplcon0 |= BPLCON0_LACE; nuclear@0: if(flags & GFX_HAM) bplcon0 |= BPLCON0_HOMOD; nuclear@0: if(flags & GFX_DBLPF) bplcon0 |= BPLCON0_DBLPF; nuclear@0: nuclear@0: REG_BPLCON0 = bplcon0; nuclear@0: REG_BPLCON1 = 0; /* h-scroll */ nuclear@0: REG_DIWSTART = 0x2c81; /* 81h horiz start, 2ch vertical start */ nuclear@0: REG_DIWSTOP = 0x2cc1; nuclear@0: REG_DDFSTART = (flags & GFX_HIRES) ? 0x3c : 0x38; nuclear@0: REG_DDFSTOP = (flags & GFX_HIRES) ? 0xd4 : 0xd0; nuclear@0: nuclear@0: gfx_wait_vblank(); nuclear@0: gfx_begin_copperlist(); nuclear@0: add_copper(COPPER_END); nuclear@0: nuclear@3: logmsg("starting DMA\n"); nuclear@0: REG_DMACON = SETBITS(DMA_BPL | DMA_COPPER | DMA_MASTER); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: void gfx_shutdown(void) nuclear@0: { nuclear@0: REG_DMACON = CLRBITS(DMA_ALL); nuclear@0: REG_DMACON = SETBITS(prev_dmacon); nuclear@0: nuclear@0: REG_INTREQ = CLRBITS(0x7fff); nuclear@0: REG_INTREQ = SETBITS(prev_intreq); nuclear@0: nuclear@0: REG_ADKCON = CLRBITS(0x7fff); nuclear@0: REG_ADKCON = SETBITS(prev_adkcon); nuclear@0: nuclear@0: REG_INTENA = CLRBITS(INTEN_ALL); nuclear@0: REG_INTENA = SETBITS(prev_intena); nuclear@0: nuclear@0: if(framebuf && own_framebuf) { nuclear@0: FreeMem(framebuf, fbsize); nuclear@0: } nuclear@0: framebuf = 0; nuclear@0: nuclear@11: if(vbint) { nuclear@11: RemIntServer(INTR_VERTB, vbint); nuclear@11: free(vbint); nuclear@11: vbint = 0; nuclear@11: } nuclear@11: nuclear@0: cleanup_copper(); nuclear@0: Permit(); nuclear@11: nuclear@11: if(init_flags & GFX_ILACE) { nuclear@11: printf("fields shown - long: %u / short: %u\n", long_fields, short_fields); nuclear@11: } nuclear@0: } nuclear@0: nuclear@0: int gfx_screen_width(void) nuclear@0: { nuclear@0: return scr_width; nuclear@0: } nuclear@0: nuclear@0: int gfx_screen_height(void) nuclear@0: { nuclear@0: return scr_height; nuclear@0: } nuclear@0: nuclear@0: void *gfx_set_framebuffer(void *fb, int width, int height) nuclear@0: { nuclear@0: /*unsigned int bpl_scanline_sz = width / 8;*/ nuclear@0: unsigned long sz = width * height / 8 * num_bitplanes; nuclear@0: uint32_t bpladdr; nuclear@0: uint16_t bplmod; nuclear@0: nuclear@0: if(framebuf && own_framebuf) { nuclear@0: FreeMem(framebuf, fbsize); nuclear@0: } nuclear@0: nuclear@0: if(fb) { nuclear@0: framebuf = fb; nuclear@0: own_framebuf = 0; nuclear@0: } else { nuclear@11: if(!(framebuf = AllocMem(sz, MEMF_CHIP | MEMF_CLEAR))) { nuclear@0: logmsg("gfx_set_framebuffer failed to allocate %lu bytes of chip mem for framebuffer\n", sz); nuclear@0: return 0; nuclear@0: } nuclear@0: own_framebuf = 1; nuclear@0: } nuclear@0: nuclear@0: fb_width = width; nuclear@0: fb_height = height; nuclear@0: fbsize = sz; nuclear@0: nuclear@0: bpladdr = (uint32_t)framebuf; nuclear@0: logmsg("bitplane address: %lx\n", (unsigned long)bpladdr); nuclear@0: nuclear@4: bplmod = (fb_width - scr_width) / 8 + fb_width / 8 * (num_bitplanes - 1); nuclear@11: if(init_flags & GFX_ILACE) { nuclear@11: bplmod += fb_width / 8 * num_bitplanes; nuclear@11: } nuclear@0: REG_BPL1MOD = bplmod; nuclear@0: REG_BPL2MOD = bplmod; nuclear@0: nuclear@0: /* nuclear@0: REG32_BPL1PT = bpladdr; bpladdr += bpl_scanline_sz; nuclear@0: REG32_BPL2PT = bpladdr; bpladdr += bpl_scanline_sz; nuclear@0: REG32_BPL3PT = bpladdr; bpladdr += bpl_scanline_sz; nuclear@0: REG32_BPL4PT = bpladdr; bpladdr += bpl_scanline_sz; nuclear@0: REG32_BPL5PT = bpladdr; bpladdr += bpl_scanline_sz; nuclear@0: REG32_BPL6PT = bpladdr; nuclear@0: */ nuclear@0: return framebuf; nuclear@0: } nuclear@0: nuclear@0: void *gfx_get_framebuffer(void) nuclear@0: { nuclear@0: return framebuf; nuclear@0: } nuclear@0: nuclear@0: int gfx_framebuffer_width(void) nuclear@0: { nuclear@0: return fb_width; nuclear@0: } nuclear@0: nuclear@0: int gfx_framebuffer_height(void) nuclear@0: { nuclear@0: return fb_height; nuclear@0: } nuclear@0: nuclear@0: void gfx_begin_copperlist(void) nuclear@0: { nuclear@0: int i; nuclear@0: uint32_t bpladdr; nuclear@11: uint16_t reg_bplptr = REGN_BPL1PTH; nuclear@0: bpladdr = (uint32_t)framebuf; nuclear@0: nuclear@11: REG_INTENA = CLRBITS(INTEN_VERTB); nuclear@11: nuclear@0: for(i=0; i> 16)); nuclear@11: reg_bplptr += 2; nuclear@11: add_copper(COPPER_MOVE(reg_bplptr, bpladdr)); nuclear@11: reg_bplptr += 2; nuclear@5: bpladdr += fb_width / 8; nuclear@0: } nuclear@11: REG_INTENA = SETBITS(INTEN_VERTB); nuclear@0: } nuclear@0: nuclear@0: static int mouse_bnstate(void) nuclear@0: { nuclear@0: return (REG_CIAA_PORTA & CIAA_PA_FIR0) ? 0 : 1; nuclear@0: } nuclear@0: nuclear@0: int gfx_next_event(union gfx_event *ev, int block) nuclear@0: { nuclear@0: /* TODO */ nuclear@0: if(block) { nuclear@0: while(!mouse_bnstate()); nuclear@0: ev->type = GFX_EV_QUIT; nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: if(mouse_bnstate()) { nuclear@0: ev->type = GFX_EV_QUIT; nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: void gfx_wait_vpos(int x) nuclear@0: { nuclear@0: x <<= 8; nuclear@0: while((REG32_VPOSR & 0x1ff00) < x); nuclear@0: } nuclear@0: nuclear@0: void gfx_wait_vblank(void) nuclear@0: { nuclear@0: gfx_wait_vpos(300); nuclear@0: } nuclear@3: nuclear@3: void gfx_show_image(struct ham_image *img) nuclear@3: { nuclear@4: int i, j, k, fbwidth, fbheight, ncolors, prev_line; nuclear@4: unsigned char *fbptr = gfx_get_framebuffer(); nuclear@4: struct palchange *chg = img->chglist; nuclear@4: nuclear@4: fbwidth = gfx_framebuffer_width(); nuclear@4: fbheight = gfx_framebuffer_height(); nuclear@4: nuclear@4: logmsg("showing ham image %dx%d\n", fbwidth, fbheight); nuclear@4: nuclear@4: memcpy(fbptr, img->pixels, fbwidth * fbheight / 8 * num_bitplanes); nuclear@4: nuclear@4: /* create copper list that handles the palette */ nuclear@4: clear_copper(); nuclear@4: gfx_begin_copperlist(); nuclear@4: /* initial palette at the start of frame */ nuclear@4: for(i=0; i<16; i++) { nuclear@4: add_copper(COPPER_MOVE(REGN_COLOR(i), img->palette[i])); nuclear@4: logmsg("copper palette[%d]: %x\n", i, (unsigned int)img->palette[i]); nuclear@4: } nuclear@4: /* add copper instructions for palette changes according to the image changelist */ nuclear@4: prev_line = -1; nuclear@4: while(chg) { nuclear@4: assert(chg->line >= prev_line); nuclear@4: if(chg->line != prev_line) { nuclear@6: if(chg->line > 255 && prev_line < 255) { nuclear@6: add_copper(COPPER_VWAIT(255)); nuclear@6: } nuclear@4: prev_line = chg->line; nuclear@4: add_copper(COPPER_VWAIT(chg->line)); nuclear@4: } nuclear@4: add_copper(COPPER_MOVE(REGN_COLOR(chg->entry >> 12), chg->entry & 0xfff)); nuclear@6: chg = chg->next; nuclear@4: } nuclear@4: add_copper(COPPER_END); nuclear@3: } nuclear@11: nuclear@11: static __amigainterrupt void vblank_intr() nuclear@11: { nuclear@11: if(init_flags & GFX_ILACE) { nuclear@11: int i; nuclear@11: uint32_t bpladdr; nuclear@11: uint16_t reg_bplptr = REGN_BPL1PTH; nuclear@11: bpladdr = (uint32_t)framebuf; nuclear@11: nuclear@11: /* 0: when long frame flag is set in VPOS */ nuclear@11: scr_field = REG_VPOSR & 0x8000; nuclear@11: if(scr_field) { nuclear@11: bpladdr += fb_width / 8 * num_bitplanes; nuclear@11: ++long_fields; nuclear@11: } else { nuclear@11: ++short_fields; nuclear@11: } nuclear@11: nuclear@11: if(coplist_bplptr[0]) { nuclear@11: for(i=0; i> 16); nuclear@11: reg_bplptr += 2; nuclear@11: coplist_bplptr[i][1] = COPPER_MOVE(reg_bplptr, bpladdr); nuclear@11: reg_bplptr += 2; nuclear@11: bpladdr += fb_width / 8; nuclear@11: } nuclear@11: } nuclear@11: } nuclear@11: /* TODO read mouse */ nuclear@11: }