~atomet/TeMaC

b4a851d7288efa0c38d8c5ebd6825c2fd09719f3 — NeoTEo 4 months ago 5ed7668
move screen code to own .c and .h
5 files changed, 157 insertions(+), 139 deletions(-)

M makefile
A src/screen.c
A src/screen.h
M src/tema.h
M src/temu.c
M makefile => makefile +4 -1
@@ 9,7 9,7 @@ all: temu
test: test.o tema.o
	cc $(CFLAGS) -o $@ $^

temu: temu.o tema.o
temu: temu.o tema.o screen.o
	cc $(SDLFLAGS) -o $@ -Isrc $^

test.o: src/test.c


@@ 21,6 21,9 @@ temu.o: src/temu.c
tema.o: src/tema.c 
	cc $(CFLAGS) -Isrc -c $<

screen.o: src/screen.c 
	cc $(CFLAGS) -Isrc -c $<

.PHONY: clean

clean:

A src/screen.c => src/screen.c +104 -0
@@ 0,0 1,104 @@
#include <stdio.h>
#include <stdlib.h>
#include "tema.h"
#include "screen.h"

void composite(TScreen *scr) {
	uint8 *bg = scr->l0.data;
	uint8 *fg = scr->l1.data;

	for(int y=0;y<scr->hgt;y++) {
		for(int x=0;x<scr->wid;x++) {
			int idx = y*scr->wid+x;
			uint8 *source = fg[idx] ? fg : bg ; 
			scr->comp[y*scr->wid+x] = source[idx] ? 0x00FFFF00 : 0x00000000;
		}
	}
}

void blit_sprite(TScreen* t, uint8* l, uint16 xpos, uint16 ypos, uint8 *dat) {

	uint8 cols = min(t->wid-xpos,8); 

	for(int r=ypos;r<min(ypos+8,t->hgt);r++) {
		for(uint8 sp=0;sp<cols;sp++) {
			l[r*t->wid+xpos+sp] = *dat&(0x80>>sp) ? 0xFF : 0x00; //! this should be a color index
		}	
		dat++;
	}
}

void set_pixel(TScreen* t, uint8* l, uint8 cidx, uint16 xpos, uint16 ypos) {
	//printf("set pixel at %d,%d to 0x%02X @ offset %d\n",xpos, ypos,cidx,ypos*t->wid+xpos);
	l[ypos*t->wid+xpos] = cidx;
}

// display_write expects TeMa pointer, port number, value to write.
void display_write(TeMa *t,uint8 p,uint8 v) {
	//printf("display_write port: 0x%02X\n",p);
	uint8 *d = &t->device[0x20];
	switch(p) {
		case 0x02: case 0x03: {	// set tema display width
			uint16 wid = BYTES2SHORT(d+0x02);
			printf("display_write received display width: 0x%02X\n",wid);
			if(wid > MAXTWID) { printf("WARNING: display width of %d exceeds maximum of %d\n",wid,MAXTWID); break; }
			size_tscreen(wid,scr.hgt);		
			//update_window();
			break;
		}
		case 0x04: case 0x05: {
			uint16 hgt = BYTES2SHORT(d+0x04);
			printf("display_write received display height: 0x%02X\n",hgt);
			if(hgt > MAXTHGT) { printf("WARNING: display height of %d exceeds maximum of %d\n",hgt,MAXTHGT); break; }
			size_tscreen(scr.wid,hgt);		
			//update_window();
			break;
		}
		case 0x0E: { // cidx (and x, y position)
			// at this point the display device buffer is assumed to contain the x and y positions
			uint16 xpos = BYTES2SHORT(d+0x08), ypos = BYTES2SHORT(d+0x0A);
			Layer* layer = *(d+0x0E) & 0x4 ? &scr.l1 : &scr.l0;
			//printf("display_write received clut info: about to place a pixel of clut idx 0x%02X at 0x%04X,0x%04X\n",v,xpos,ypos);
			if(xpos>=scr.wid || ypos>=scr.hgt) break;
			set_pixel(&scr, layer->data,v, xpos, ypos);
			layer->dirty = 1; 
			break;
		}
		case 0x0F: // dma
		{
			// at this point the display device buffer is assumed to contain the x and y positions and an address
			uint16 xpos = BYTES2SHORT(d+0x08), ypos = BYTES2SHORT(d+0x0A), adr = BYTES2SHORT(d+0x0C);
			Layer* layer = *(d+0x0F) & 0x4 ? &scr.l1 : &scr.l0;
			//char* layerid = *(d+0x0F) & 0x4 ? "fg" : "bg";
			//printf("display_write received dma: about to blit %s at %d,%d\n",layerid,xpos,ypos);
			if(xpos>=scr.wid || ypos>=scr.hgt) break;

			blit_sprite(&scr, layer->data, xpos, ypos,&t->ram[adr]) ;
			layer->dirty = 1;
			break; 			 
		}
	}
}

void tdisplay_clean() {
	free(scr.l0.data);
	free(scr.l1.data);
	free(scr.comp);
}

void size_tscreen(uint16 wid, uint16 hgt) {
	printf("size_tscreen\n");
	scr.bpp = sizeof(uint32);	// RGB8888
	if(wid < 0x8 || wid > 0x400 || hgt < 0x8 || hgt > 0x400) return;

	uint8* l0 = realloc(scr.l0.data,wid*hgt);
	uint8* l1 = realloc(scr.l1.data,wid*hgt);
	uint32* comp = realloc(scr.comp,wid*hgt*scr.bpp);

	if(!l0 || !l1 || !comp) return;
	
	scr.wid = wid; scr.hgt = hgt;
	scr.l0.data = l0; scr.l1.data = l1; scr.comp = comp;
	scr.bodge = 1;
	printf("thres %d, tvres %d, bodge %d\n",scr.wid,scr.hgt,scr.bodge);
}

A src/screen.h => src/screen.h +26 -0
@@ 0,0 1,26 @@
#include <stdio.h>

typedef struct {
	uint8* data;
	uint8 dirty;
} Layer;

typedef struct {
	uint16 wid, hgt;
	uint8 bpp;
	Layer l0, l1;	
	uint32* comp; 
	uint8 bodge; 	//! temp flag to signal size change
} TScreen;

#define MAXTWID 0x400 
#define MAXTHGT	0x400 

TScreen scr;

void size_tscreen(uint16 wid, uint16 hgt);
void blit_sprite(TScreen* t, uint8* l, uint16 xpos, uint16 ypos, uint8 *dat); 
void display_write(TeMa *t,uint8 p,uint8 v); 
void tdisplay_clean(); 
void size_tscreen(uint16 wid, uint16 hgt); 
void composite(TScreen *scr); 

M src/tema.h => src/tema.h +11 -0
@@ 1,9 1,20 @@
// Common definitions

#define min(a,b) \
   ({ __typeof__ (a) _a = (a); \
       __typeof__ (b) _b = (b); \
     _a < _b ? _a : _b; })
 #define max(a,b) \
   ({ __typeof__ (a) _a = (a); \
       __typeof__ (b) _b = (b); \
     _a > _b ? _a : _b; })

// TeMa is big-endian

//! should use stdint.h and uintN_t instead.
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;	//! eg. use uint32_t instead.

typedef signed char sint8;
typedef signed short sint16;

M src/temu.c => src/temu.c +12 -138
@@ 1,8 1,10 @@
#include "tema.h"
#include <stdio.h>
#include <stdlib.h>
#include <SDL2/SDL.h>

#include "tema.h"
#include "screen.h"

//device ids 
// host 		0x00 
// console 		0x10


@@ 18,60 20,15 @@
static uint16 whres = 640;
static uint16 wvres = 480;

// The default resolution of TeMa inside the host window
static uint16 thres = 640;
static uint16 tvres = 480;
#define MAXTWID 0x400 
#define MAXTHGT	0x400 
//static uint8 bpp=4;	// default bits per pixel
static uint8 wresx = 1;
void update_window();
void size_tscreen(uint16 wid, uint16 hgt);

#define min(a,b) \
   ({ __typeof__ (a) _a = (a); \
       __typeof__ (b) _b = (b); \
     _a < _b ? _a : _b; })
 #define max(a,b) \
   ({ __typeof__ (a) _a = (a); \
       __typeof__ (b) _b = (b); \
     _a > _b ? _a : _b; })

SDL_Renderer *renderer;
SDL_Window *window;
SDL_Texture *texture;

//! move TScreen code to a separate file once finalized

typedef struct {
	uint8* data;
	uint8 dirty;
} Layer;

typedef struct {
	uint16 wid, hgt;
	uint8 bpp;
	Layer l0, l1;	
	Uint32* comp; 
} TScreen;


TScreen scr;

void composite(TScreen *scr) {
	uint8 *bg = scr->l0.data;
	uint8 *fg = scr->l1.data;

	for(int y=0;y<scr->hgt;y++) {
		for(int x=0;x<scr->wid;x++) {
			int idx = y*scr->wid+x;
			uint8 *source = fg[idx] ? fg : bg ; 
			scr->comp[y*scr->wid+x] = source[idx] ? 0x00FFFF00 : 0x00000000;
		}
	}
}


void window_init(uint16 win_hres, uint16 win_vres, uint16 tema_hres, uint16 tema_vres) {
	SDL_Init(SDL_INIT_VIDEO);	
	SDL_ShowCursor(SDL_DISABLE);


@@ 80,23 37,6 @@ void window_init(uint16 win_hres, uint16 win_vres, uint16 tema_hres, uint16 tema
	renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE );
}

void blit_sprite(TScreen* t, uint8* l, uint16 xpos, uint16 ypos, uint8 *dat) {

	uint8 cols = min(t->wid-xpos,8); 

	for(int r=ypos;r<min(ypos+8,t->hgt);r++) {
		for(uint8 sp=0;sp<cols;sp++) {
			l[r*t->wid+xpos+sp] = *dat&(0x80>>sp) ? 0xFF : 0x00; //! this should be a color index
		}	
		dat++;
	}
}

void set_pixel(TScreen* t, uint8* l, uint8 cidx, uint16 xpos, uint16 ypos) {
	//printf("set pixel at %d,%d to 0x%02X @ offset %d\n",xpos, ypos,cidx,ypos*t->wid+xpos);
	l[ypos*t->wid+xpos] = cidx;
}

void window_clean() {
	// Clean up
	SDL_DestroyTexture(texture); texture = NULL;


@@ 105,7 45,6 @@ void window_clean() {
	SDL_Quit();
}


static void host_write(TeMa *t,uint8 p,uint8 v) {
	switch(p) {
		case 0x08: // red components of host 4-colour (4 bits per colour) clut


@@ 136,54 75,6 @@ static void console_write(uint8 p,uint8 v) {
	fflush(f);
}

// display_write expects TeMa pointer, port number, value to write.
static void display_write(TeMa *t,uint8 p,uint8 v) {
	//printf("display_write port: 0x%02X\n",p);
	uint8 *d = &t->device[0x20];
	switch(p) {
		case 0x02: case 0x03: {	// set tema display width
			uint16 wid = BYTES2SHORT(d+0x02);
			printf("display_write received display width: 0x%02X\n",wid);
			if(wid > MAXTWID) { printf("WARNING: display width of %d exceeds maximum of %d\n",wid,MAXTWID); break; }
			thres = wid; 
			size_tscreen(wid,scr.hgt);		
			update_window();
			break;
		}
		case 0x04: case 0x05: {
			uint16 hgt = BYTES2SHORT(d+0x04);
			printf("display_write received display height: 0x%02X\n",hgt);
			if(hgt > MAXTHGT) { printf("WARNING: display height of %d exceeds maximum of %d\n",hgt,MAXTHGT); break; }
			tvres = hgt; 
			size_tscreen(scr.wid,hgt);		
			update_window();
			break;
		}
		case 0x0E: { // cidx (and x, y position)
			// at this point the display device buffer is assumed to contain the x and y positions
			uint16 xpos = BYTES2SHORT(d+0x08), ypos = BYTES2SHORT(d+0x0A);
			Layer* layer = *(d+0x0E) & 0x4 ? &scr.l1 : &scr.l0;
			//printf("display_write received clut info: about to place a pixel of clut idx 0x%02X at 0x%04X,0x%04X\n",v,xpos,ypos);
			if(xpos>=scr.wid || ypos>=scr.hgt) break;
			set_pixel(&scr, layer->data,v, xpos, ypos);
			layer->dirty = 1; 
			break;
		}
		case 0x0F: // dma
		{
			// at this point the display device buffer is assumed to contain the x and y positions and an address
			uint16 xpos = BYTES2SHORT(d+0x08), ypos = BYTES2SHORT(d+0x0A), adr = BYTES2SHORT(d+0x0C);
			Layer* layer = *(d+0x0F) & 0x4 ? &scr.l1 : &scr.l0;
			//char* layerid = *(d+0x0F) & 0x4 ? "fg" : "bg";
			//printf("display_write received dma: about to blit %s at %d,%d\n",layerid,xpos,ypos);
			if(xpos>=scr.wid || ypos>=scr.hgt) break;

			blit_sprite(&scr, layer->data, xpos, ypos,&t->ram[adr]) ;
			layer->dirty = 1;
			break; 			 
		}
	}
}


// TeMu -> TeMa


@@ 264,8 155,8 @@ void update_bit(uint8* val, uint8 bit, uint8 set) {
static uint8 controller_state = 0;
void update_controller(int sym, uint8* state, uint8 set) {
	switch(sym) {
		case SDLK_LCTRL: case SDLK_RCTRL:   update_bit(state, 0x01, set); break;
		case SDLK_LALT: case SDLK_RALT:     update_bit(state, 0x02, set); break;
		case SDLK_LCTRL:  case SDLK_RCTRL:  update_bit(state, 0x01, set); break;
		case SDLK_LALT:   case SDLK_RALT:   update_bit(state, 0x02, set); break;
		case SDLK_LSHIFT: case SDLK_RSHIFT: update_bit(state, 0x04, set); break;
		case SDLK_HOME: 					update_bit(state, 0x08, set); break;
		case SDLK_UP: 						update_bit(state, 0x10, set); break;


@@ 362,10 253,11 @@ int temu_run(TeMa* tema) {

		// should we read the vector outside the loop? It would mean TeMa could change it without effect, so probably no.
		uint16 display_handler = BYTES2SHORT(&tema->device[0x20]);

		if(scr.bodge == 1) { printf("updating window\n"); update_window(); scr.bodge=0; }
			
		if(display_handler) {
			run(tema, display_handler);

			if(scr.l0.dirty || scr.l1.dirty) {
				
				composite(&scr); 


@@ 391,32 283,13 @@ int temu_run(TeMa* tema) {
	return 1;
}

void tdisplay_clean() {
	free(scr.l0.data);
	free(scr.l1.data);
	free(scr.comp);
}

void size_tscreen(uint16 wid, uint16 hgt) {

	scr.bpp = sizeof(Uint32);	// RGB8888
	if(wid < 0x8 || wid > 0x400 || hgt < 0x8 || hgt > 0x400) return;

	uint8* l0 = realloc(scr.l0.data,wid*hgt);
	uint8* l1 = realloc(scr.l1.data,wid*hgt);
	Uint32* comp = realloc(scr.comp,wid*hgt*scr.bpp);

	if(!l0 || !l1 || !comp) return;

	scr.wid = wid; scr.hgt = hgt;
	scr.l0.data = l0; scr.l1.data = l1; scr.comp = comp;
}


void update_window() {
	printf("update_window !!!!!!!!!!\n");
	uint16 thres = scr.wid; uint16 tvres = scr.hgt;
	whres = thres*wresx; wvres = tvres*wresx;
	if( texture != NULL ) SDL_DestroyTexture(texture);

	printf("wresx is %d: setting whres and wvres to %d,%d\n",wresx,whres,wvres);
	// renderer is the size of the insides of the host window.
	SDL_RenderSetLogicalSize(renderer, thres, tvres);



@@ 437,7 310,7 @@ int main(int argc, char *argv[]) {
	char *rompath= argv[1];

	// init stuff	

	scr.wid = 640; scr.hgt = 480;
	TeMa tema;
	// calloc inits to 0
	inittema(&tema, (uint8 *)calloc(RAMBYTES, sizeof(uint8)), inbus, outbus);


@@ 455,6 328,7 @@ int main(int argc, char *argv[]) {
	//db_ramprint(tema.ram.data,0x0000, romsize,0x8);

	// create display
	uint16 thres = scr.wid; uint16 tvres = scr.hgt;
	whres = thres*wresx; wvres = tvres*wresx;
	window_init(whres, wvres, thres, tvres);
	size_tscreen(thres, tvres);