diff --git a/src/Makefile b/src/Makefile index 2513e87..189dd36 100644 --- a/src/Makefile +++ b/src/Makefile @@ -21,7 +21,7 @@ # SOFTWARE. CC?=cc -CFLAGS=-std=gnu11 -O3 -Wall -Wextra -Werror -Wno-unused-parameter +CFLAGS=-std=gnu11 -O3 -g -Wall -Wextra -Werror -Wno-unused-parameter LDFLAGS=-g -L/usr/local/lib EWM_EXECUTABLE=ewm @@ -49,10 +49,15 @@ MEM_BENCH_SOURCES=cpu.c ins.c mem.c fmt.c utl.c mem_bench.c MEM_BENCH_OBJECTS=$(MEM_BENCH_SOURCES:.c=.o) MEM_BENCH_LIBS= -all: $(EWM_SOURCES) $(EWM_EXECUTABLE) $(CPU_TEST_SOURCES) $(CPU_TEST_EXECUTABLE) $(SCR_TEST_EXECUTABLE) $(CPU_BENCH) $(MEM_BENCH) +CHR_TEST=chr_test +CHR_TEST_SOURCES=chr.c chr_test.c +CHR_TEST_OBJECTS=$(CHR_TEST_SOURCES:.c=.o) +CHR_TEST_LIBS=-lSDL2 + +all: $(EWM_SOURCES) $(EWM_EXECUTABLE) $(CPU_TEST_SOURCES) $(CPU_TEST_EXECUTABLE) $(SCR_TEST_EXECUTABLE) $(CHR_TEST) $(CPU_BENCH) $(MEM_BENCH) clean: - rm -f $(EWM_OBJECTS) $(EWM_EXECUTABLE) $(CPU_TEST_OBJECTS) $(CPU_TEST_EXECUTABLE) $(SCR_TEST_OBJECTS) $(SCR_TEST_EXECUTABLE) $(CPU_BENCH) $(MEM_BENCH) + rm -f $(EWM_OBJECTS) $(EWM_EXECUTABLE) $(CPU_TEST_OBJECTS) $(CPU_TEST_EXECUTABLE) $(SCR_TEST_OBJECTS) $(SCR_TEST_EXECUTABLE) $(CHR_TEST) $(CHR_TEST_OBJECTS) $(CPU_BENCH) $(CPU_BENCH_OBJECTS) $(MEM_BENCH) $(MEM_BENCH_OBJECTS) $(EWM_EXECUTABLE): $(EWM_OBJECTS) $(CC) $(LDFLAGS) $(EWM_OBJECTS) $(EWM_LIBS) -o $@ @@ -69,5 +74,8 @@ $(CPU_BENCH): $(CPU_BENCH_OBJECTS) $(MEM_BENCH): $(MEM_BENCH_OBJECTS) $(CC) $(LDFLAGS) $(MEM_BENCH_OBJECTS) $(MEM_BENCH_LIBS) -o $@ +$(CHR_TEST): $(CHR_TEST_OBJECTS) + $(CC) $(LDFLAGS) $(CHR_TEST_OBJECTS) $(CHR_TEST_LIBS) -o $@ + .c.o: $(CC) $(CFLAGS) $< -c -o $@ diff --git a/src/boo.c b/src/boo.c index 8d48232..3bf543c 100644 --- a/src/boo.c +++ b/src/boo.c @@ -68,7 +68,7 @@ int ewm_boo_main(int argc, char **argv) { return 1; } - SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE); if (renderer == NULL) { fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError()); return 1; @@ -78,7 +78,7 @@ int ewm_boo_main(int argc, char **argv) { // We only need a tty to display the menu - struct ewm_tty_t *tty = ewm_tty_create(renderer); + struct ewm_tty_t *tty = ewm_tty_create(window, renderer); // Main loop diff --git a/src/chr.c b/src/chr.c index c55b8c9..2f76ffb 100644 --- a/src/chr.c +++ b/src/chr.c @@ -65,8 +65,14 @@ static void _set_pixel(SDL_Surface * surface, int x, int y, Uint32 color) { *pixel = color; } -static SDL_Texture *_generate_texture(SDL_Renderer *renderer, uint8_t rom_data[2048], int c, bool inverse) { - SDL_Texture *texture = NULL; +static SDL_Surface *_generate_surface(SDL_Renderer *renderer, uint8_t rom_data[2048], int c, bool inverse, uint32_t color) { + SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, 7*3, 8*3, 32, SDL_PIXELFORMAT_ARGB8888); + if (surface == NULL) { + fprintf(stderr, "[CHR] Cannot create RGBSurface: %s\n", SDL_GetError()); + return NULL; + } + + SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE); uint8_t character_data[8]; for (int i = 0; i < 8; i++) { @@ -76,27 +82,39 @@ static SDL_Texture *_generate_texture(SDL_Renderer *renderer, uint8_t rom_data[2 } } - SDL_Surface *surface = SDL_CreateRGBSurface(0, 7, 8, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); - if (surface != NULL) { - for (int y = 0; y < 8; y++) { - for (int x = 0; x < 7; x++) { - if (character_data[y] & (1 << x)) { - _set_pixel(surface, (6-x), y, 0xffffffff); - } + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 7; x++) { + if (character_data[y] & (1 << x)) { + int px = (6-x) * 3, py = y * 3; + + _set_pixel(surface, px+0, py+0, color); + _set_pixel(surface, px+1, py+0, color); + _set_pixel(surface, px+2, py+0, color); + + _set_pixel(surface, px+0, py+1, color); + _set_pixel(surface, px+1, py+1, color); + _set_pixel(surface, px+2, py+1, color); + + _set_pixel(surface, px+0, py+2, color); + _set_pixel(surface, px+1, py+2, color); + _set_pixel(surface, px+2, py+2, color); } } - texture = SDL_CreateTextureFromSurface(renderer, surface); - if (texture == NULL) { - fprintf(stderr, "Cannot generate RGBSurface: %s\n", SDL_GetError()); - } - } else { - fprintf(stderr, "Cannot generate Texture: %s\n", SDL_GetError()); } + return surface; +} + +static SDL_Texture *_generate_texture(SDL_Renderer *renderer, SDL_Surface *surface) { + SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface); + if (texture == NULL) { + fprintf(stderr, "[CHR] Cannot generate Texture from Surface: %s\n", SDL_GetError()); + return NULL; + } return texture; } -static int ewm_chr_init(struct ewm_chr_t *chr, char *rom_path, int rom_type, SDL_Renderer *renderer) { +static int ewm_chr_init(struct ewm_chr_t *chr, char *rom_path, int rom_type, SDL_Renderer *renderer, uint32_t color) { if (rom_type != EWM_CHR_ROM_TYPE_2716) { return -1; } @@ -107,36 +125,50 @@ static int ewm_chr_init(struct ewm_chr_t *chr, char *rom_path, int rom_type, SDL return -1; } + // This is not great. I think what should happen is that this + // module just creates normal and inverse surfaces and textures in + // exact ROM order and then scr.c and tty.c can map an ASCII value + // to a specific ROM character. That keeps this module simple and + // moves more logic into the machine specific modules. That also + // solves the problem that you can currently print inverse + // characters on the Apple 1. + // Normal Text for (int c = 0; c < 32; c++) { - chr->characters[0xc0 + c] = _generate_texture(renderer, rom_data, c, false); + chr->surfaces[0xc0 + c] = _generate_surface(renderer, rom_data, c, false, color); + chr->textures[0xc0 + c] = _generate_texture(renderer, chr->surfaces[0xc0 + c]); } for (int c = 32; c < 64; c++) { - chr->characters[0xa0 + (c-32)] = _generate_texture(renderer, rom_data, c, false); + chr->surfaces[0xa0 + (c-32)] = _generate_surface(renderer, rom_data, c, false, color); + chr->textures[0xa0 + (c-32)] = _generate_texture(renderer, chr->surfaces[0xa0 + (c-32)]); } // Inverse Text for (int c = 0; c < 32; c++) { - chr->characters[0x00 + c] = _generate_texture(renderer, rom_data, c, true); + chr->surfaces[0x00 + c] = _generate_surface(renderer, rom_data, c, true, color); + chr->textures[0x00 + c] = _generate_texture(renderer, chr->surfaces[0x00 + c]); } for (int c = 32; c < 64; c++) { - chr->characters[0x20 + (c-32)] = _generate_texture(renderer, rom_data, c, true); + chr->surfaces[0x20 + (c-32)] = _generate_surface(renderer, rom_data, c, true, color); + chr->textures[0x20 + (c-32)] = _generate_texture(renderer, chr->surfaces[0x20 + (c-32)]); } // TODO Flashing - Currently simply rendered as inverse for (int c = 0; c < 32; c++) { - chr->characters[0x40 + c] = _generate_texture(renderer, rom_data, c, true); + chr->surfaces[0x40 + c] = _generate_surface(renderer, rom_data, c, true, color); + chr->textures[0x40 + c] = _generate_texture(renderer, chr->surfaces[0x40 + c]); } for (int c = 32; c < 64; c++) { - chr->characters[0x60 + (c-32)] = _generate_texture(renderer, rom_data, c, true); + chr->surfaces[0x60 + (c-32)] = _generate_surface(renderer, rom_data, c, true, color); + chr->textures[0x60 + (c-32)] = _generate_texture(renderer, chr->surfaces[0x60 + (c-32)]); } return 0; } -struct ewm_chr_t* ewm_chr_create(char *rom_path, int rom_type, SDL_Renderer *renderer) { +struct ewm_chr_t* ewm_chr_create(char *rom_path, int rom_type, SDL_Renderer *renderer, uint32_t color) { struct ewm_chr_t *chr = (struct ewm_chr_t*) malloc(sizeof(struct ewm_chr_t)); - int ret = ewm_chr_init(chr, rom_path, rom_type, renderer); + int ret = ewm_chr_init(chr, rom_path, rom_type, renderer, color); if (ret != 0) { free(chr); chr = NULL; @@ -144,6 +176,7 @@ struct ewm_chr_t* ewm_chr_create(char *rom_path, int rom_type, SDL_Renderer *ren return chr; } + #if 0 int main() { struct ewm_chr_t *chr = ewm_chr_create("rom/3410036.bin", EWM_CHR_ROM_TYPE_2716); diff --git a/src/chr.h b/src/chr.h index a36d8b3..44abdbe 100644 --- a/src/chr.h +++ b/src/chr.h @@ -28,9 +28,10 @@ #define EWM_CHR_ROM_TYPE_2716 (2716) struct ewm_chr_t { - SDL_Texture* characters[256]; + SDL_Surface* surfaces[256]; + SDL_Texture* textures[256]; }; -struct ewm_chr_t* ewm_chr_create(char *rom_path, int rom_type, SDL_Renderer *renderer); +struct ewm_chr_t* ewm_chr_create(char *rom_path, int rom_type, SDL_Renderer *renderer, uint32_t color); #endif diff --git a/src/chr_test.c b/src/chr_test.c new file mode 100644 index 0000000..54561a8 --- /dev/null +++ b/src/chr_test.c @@ -0,0 +1,59 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Stefan Arentz - http://github.com/st3fan/ewm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include + +#include "chr.h" + +int main() { + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + fprintf(stderr, "[CHR] Failed to initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + + SDL_Window *window = SDL_CreateWindow("chr_test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 280*3, 192*3, SDL_WINDOW_SHOWN); + if (window == NULL) { + fprintf(stderr, "[CHR] Failed create window: %s\n", SDL_GetError()); + exit(1); + } + + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + + SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE); + if (renderer == NULL) { + fprintf(stderr, "[CHR] Failed to create renderer: %s\n", SDL_GetError()); + exit(1); + } + + uint32_t color = SDL_MapRGB(SDL_GetWindowSurface(window)->format, 47, 249, 64); + + struct ewm_chr_t *chr = ewm_chr_create("rom/3410036.bin", EWM_CHR_ROM_TYPE_2716, renderer, color); + if (chr == NULL) { + fprintf(stderr, "[CHR] Failed to load Character ROM %s\n", "rom/3410036.bin"); + exit(1); + } + + // TODO Blit the whole character rom as textures and then as surfaces + + return 0; +} diff --git a/src/one.c b/src/one.c index cf2d253..e548cbe 100644 --- a/src/one.c +++ b/src/one.c @@ -40,7 +40,7 @@ static void ewm_one_pia_callback(struct ewm_pia_t *pia, void *obj, uint8_t ddr, ewm_tty_write(one->tty, v); } -static int ewm_one_init(struct ewm_one_t *one, int model, SDL_Renderer *renderer) { +static int ewm_one_init(struct ewm_one_t *one, int model, SDL_Window *window, SDL_Renderer *renderer) { memset(one, 0, sizeof(struct ewm_one_t)); one->model = model; switch (model) { @@ -48,7 +48,7 @@ static int ewm_one_init(struct ewm_one_t *one, int model, SDL_Renderer *renderer one->cpu = cpu_create(EWM_CPU_MODEL_6502); cpu_add_ram(one->cpu, 0x0000, 8 * 1024 - 1); cpu_add_rom_file(one->cpu, 0xff00, "rom/apple1.rom"); - one->tty = ewm_tty_create(renderer); + one->tty = ewm_tty_create(window, renderer); one->pia = ewm_pia_create(one->cpu); one->pia->callback = ewm_one_pia_callback; one->pia->callback_obj = one; @@ -57,7 +57,7 @@ static int ewm_one_init(struct ewm_one_t *one, int model, SDL_Renderer *renderer one->cpu = cpu_create(EWM_CPU_MODEL_65C02); cpu_add_ram(one->cpu, 0x0000, 32 * 1024 - 1); cpu_add_rom_file(one->cpu, 0xe000, "rom/krusader.rom"); - one->tty = ewm_tty_create(renderer); + one->tty = ewm_tty_create(window, renderer); one->pia = ewm_pia_create(one->cpu); one->pia->callback = ewm_one_pia_callback; one->pia->callback_obj = one; @@ -66,6 +66,15 @@ static int ewm_one_init(struct ewm_one_t *one, int model, SDL_Renderer *renderer return 0; } +struct ewm_one_t *ewm_one_create(int model, SDL_Window *window, SDL_Renderer *renderer) { + struct ewm_one_t *one = (struct ewm_one_t*) malloc(sizeof(struct ewm_one_t)); + if (ewm_one_init(one, model, window, renderer) != 0) { + free(one); + one = NULL; + } + return one; +} + void ewm_one_destroy(struct ewm_one_t *one) { // TODO } @@ -259,17 +268,19 @@ int ewm_one_main(int argc, char **argv) { return 1; } - SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE); if (renderer == NULL) { fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError()); return 1; } + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + SDL_RenderSetLogicalSize(renderer, 280*3, 192*3); // Create the machine - struct ewm_one_t *one = ewm_one_create(model, renderer); + struct ewm_one_t *one = ewm_one_create(model, window, renderer); if (one == NULL) { fprintf(stderr, "Failed to create ewm_one_t\n"); return 1; @@ -335,11 +346,3 @@ int ewm_one_main(int argc, char **argv) { return 0; } -struct ewm_one_t *ewm_one_create(int model, SDL_Renderer *renderer) { - struct ewm_one_t *one = (struct ewm_one_t*) malloc(sizeof(struct ewm_one_t)); - if (ewm_one_init(one, model, renderer) != 0) { - free(one); - one = NULL; - } - return one; -} diff --git a/src/one.h b/src/one.h index 9876fa4..07f0e8b 100644 --- a/src/one.h +++ b/src/one.h @@ -43,7 +43,7 @@ struct ewm_one_t { struct ewm_pia_t *pia; }; -struct ewm_one_t *ewm_one_create(int type, SDL_Renderer *renderer); +struct ewm_one_t *ewm_one_create(int type, SDL_Window *window, SDL_Renderer *renderer); void ewm_one_destroy(struct ewm_one_t *one); int ewm_one_main(int argc, char **argv); diff --git a/src/scr.c b/src/scr.c index 8cb3fdf..4e84c72 100644 --- a/src/scr.c +++ b/src/scr.c @@ -31,6 +31,14 @@ #include "chr.h" #include "scr.h" +inline static void _set_pixel(SDL_Surface * surface, int x, int y, Uint32 color) { + // TODO This will break if pitch is not very predictable or weird + //uint32_t *pixel = (uint32_t*) ((uint8_t*) surface->pixels + (y * 280*3*sizeof(uint32_t)) + (x * sizeof(uint32_t))); + //*pixel = color; + uint32_t *pixel = (uint32_t*) ((uint8_t*) surface->pixels + (y * surface->pitch) + (x * sizeof(uint32_t))); + *pixel = color; +} + // Text rendering static int txt_line_offsets[24] = { @@ -41,7 +49,13 @@ static int txt_line_offsets[24] = { static inline void scr_render_character(struct scr_t *scr, int row, int column, bool flash) { uint16_t base = (scr->two->screen_page == EWM_A2P_SCREEN_PAGE1) ? 0x0400 : 0x0800; uint8_t c = scr->two->screen_txt_data[((txt_line_offsets[row] + base) + column) - 0x0400]; - if (scr->chr->characters[c] != NULL) { + if (scr->chr->textures[c] != NULL) { + SDL_Rect src; + src.x = 0; + src.y = 0; + src.w = 21; + src.h = 24; + SDL_Rect dst; dst.x = column * 21; dst.y = row * 24; @@ -61,26 +75,59 @@ static inline void scr_render_character(struct scr_t *scr, int row, int column, } if (scr->color_scheme == EWM_SCR_COLOR_SCHEME_MONOCHROME) { - SDL_SetTextureColorMod(scr->chr->characters[c], 0, 255, 0); + SDL_SetSurfaceColorMod(scr->chr->surfaces[c], 47, 249, 64); } else { - SDL_SetTextureColorMod(scr->chr->characters[c], 255, 255, 255); + SDL_SetSurfaceColorMod(scr->chr->surfaces[c], 255, 255, 255); } - SDL_RenderCopy(scr->renderer, scr->chr->characters[c], NULL, &dst); + SDL_SetSurfaceBlendMode(scr->chr->surfaces[c], SDL_BLENDMODE_NONE); + + SDL_BlitSurface(scr->chr->surfaces[c], &src, SDL_GetWindowSurface(scr->window), &dst); } } static inline void scr_render_txt_screen(struct scr_t *scr, bool flash) { + SDL_Surface *surface = SDL_GetWindowSurface(scr->window); + uint8_t *base = scr->two->screen_txt_data + (scr->two->screen_page == EWM_A2P_SCREEN_PAGE1 ? 0x0000 : 0x0400); + SDL_Surface **surfaces = scr->chr->surfaces; + SDL_Rect src; + src.x = 0; + src.y = 0; + src.w = 21; + src.h = 24; + SDL_Rect dst; + dst.x = 0; + dst.y = 0; + dst.w = 21; + dst.h = 24; + for (int row = 0; row < 24; row++) { + uint8_t *p = base + txt_line_offsets[row]; for (int column = 0; column < 40; column++) { - scr_render_character(scr, row, column, flash); + uint8_t c = *p++; + if (surfaces[c] != NULL) { + if (c >= 0x40 && c <= 0x7f) { + if (flash) { + c -= 0x40; + } else { + if (c <= 0x5f) { + c += 0x80; + } else { + c += 0x40; + } + } + } + dst.x = column * 21; + dst.y = row * 24; + SDL_BlitSurface(surfaces[c], &src, surface, &dst); + } } } } // Lores Rendering -static SDL_Color lores_colors[16] = { +static SDL_Color lores_colors_color[16] = { { 0, 0, 0, 0 }, // 0 Black { 255, 0, 255, 0 }, // 1 Magenta { 0, 0, 204, 0 }, // 2 Dark Blue @@ -99,41 +146,85 @@ static SDL_Color lores_colors[16] = { { 255, 255, 255, 0 }, // 15 White }; -static inline void scr_render_lores_block(struct scr_t *scr, int row, int column) { - uint16_t base = (scr->two->screen_page == EWM_A2P_SCREEN_PAGE1) ? 0x0400 : 0x0800; - uint8_t block = scr->two->screen_txt_data[((txt_line_offsets[row] + base) + column) - 0x0400]; - if (block != 0) { - SDL_Rect dst; - dst.x = column * 21; - dst.y = row * 24; - dst.w = 21; - dst.h = 12; - - uint8_t c = block & 0x0f; - if (c != 0) { - SDL_SetRenderDrawColor(scr->renderer, lores_colors[c].r, lores_colors[c].g, lores_colors[c].b, lores_colors[c].a); - SDL_RenderFillRect(scr->renderer, &dst); - } - - c = (block & 0xf0) >> 4; - if (c != 0) { - dst.y += 12; - SDL_SetRenderDrawColor(scr->renderer, lores_colors[c].r, lores_colors[c].g, lores_colors[c].b, lores_colors[c].a); - SDL_RenderFillRect(scr->renderer, &dst); - } - } -} +static SDL_Color lores_colors_green[16] = { + { 0, 0, 0, 0 }, // 0 Black + { 9, 87, 17, 0 }, // 1 Magenta + { 2, 22, 3, 0 }, // 2 Dark Blue + { 19, 126, 29, 0 }, // 3 Purple + { 11, 90, 18, 0 }, // 4 Dark Green + { 13, 101, 21, 0 }, // 5 Grey 1 + { 8, 74, 14, 0 }, // 6 Medium Blue + { 28, 170, 40, 0 }, // 7 Light Blue + { 15, 109, 22, 0 }, // 8 Brown + { 24, 152, 35, 0 }, // 9 Orange + { 33, 181, 45, 0 }, // 10 Grey 2 + { 34, 190, 47, 0 }, // 11 Pink + { 23, 149, 34, 0 }, // 12 Light Green + { 43, 227, 58, 0 }, // 13 Yellow + { 34, 197, 49, 0 }, // 14 Aquamarine + { 47, 249, 64, 0 }, // 15 White +}; static inline void scr_render_lgr_screen(struct scr_t *scr, bool flash) { bool mixed = (scr->two->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED); - + SDL_Surface *surface = SDL_GetWindowSurface(scr->window); + uint32_t *colors = scr->color_scheme == EWM_SCR_COLOR_SCHEME_COLOR ? scr->lores_colors_color : scr->lores_colors_green; + uint16_t base = (scr->two->screen_page == EWM_A2P_SCREEN_PAGE1) ? 0x0400 : 0x0800; + // Render graphics int rows = mixed ? 20 : 24; for (int row = 0; row < rows; row++) { for (int column = 0; column < 40; column++) { - scr_render_lores_block(scr, row, column); + + uint8_t block = scr->two->screen_txt_data[((txt_line_offsets[row] + base) + column) - 0x0400]; + if (block != 0) { + + SDL_Rect dst; + dst.x = column * 21; + dst.y = row * 24; + dst.w = 21; + dst.h = 12; + + uint8_t c = block & 0x0f; + if (c != 0) { + SDL_FillRect(surface, &dst, colors[c]); + } + + c = (block & 0xf0) >> 4; + if (c != 0) { + dst.y += 12; + SDL_FillRect(surface, &dst, colors[c]); + } + +#if 0 + int px = column * 21, py = row * 24; + + uint8_t c = block & 0x0f; + if (c != 0) { + for (int h = 0; h < 12; h++) { + for (int w = 0; w <21; w++) { + _set_pixel(surface, px+w, py+h, colors[c]); + } + } + } + + py += 12; + + c = (block & 0xf0) >> 4; + if (c != 0) { + for (int h = 0; h < 12; h++) { + for (int w = 0; w <21; w++) { + _set_pixel(surface, px+w, py+h, colors[c]); + } + } + } +#endif + + } + } } + // Render bottom 4 lines if (mixed) { for (int row = 20; row < 24; row++) { @@ -180,85 +271,91 @@ static uint16_t hgr_line_offsets[192] = { // CBBBBBBB -static SDL_Color hgr_colors[16] = { +static SDL_Color hires_colors[16] = { { 0, 0, 0, 0 }, // 0 Black - { 0, 0, 204, 0 }, // 1 Blue - { 128, 0, 128, 0 }, // 2 Purple - { 0, 100, 0, 0 }, // 3 Green - { 0, 100, 0, 0 }, // 4 Red + { 0, 150, 255, 0 }, // 1 Light Blue + { 255, 64, 255, 0 }, // 2 Purple + { 0, 249, 0, 0 }, // 3 Green + { 255, 147, 0, 0 }, // 4 Red { 255, 255, 255, 0 } // 5 White }; -inline static void scr_render_hgr_line_green(struct scr_t *scr, int line, uint16_t line_base) { +inline static void scr_render_hgr_line_green(struct scr_t *scr, int line, uint16_t line_base, SDL_Surface *surface) { + uint32_t green = scr->text_color; int x = 0; for (int i = 0; i < 40; i++) { uint8_t c = scr->two->screen_hgr_data[line_base + i]; for (int j = 0; j < 7; j++) { - SDL_Rect dst; - dst.x = x * 3; - dst.y = line * 3; - dst.w = 3; - dst.h = 3; - if (c & (1 << j)) { - SDL_SetRenderDrawColor(scr->renderer, 0, 255, 0, 0); - } else { - SDL_SetRenderDrawColor(scr->renderer, 0, 0, 0, 0); - } - SDL_RenderFillRect(scr->renderer, &dst); + uint32_t color = (c & (1 << j)) ? green : 0; + + int px = x * 3, py = line * 3; + + _set_pixel(surface, px+0, py+0, color); + _set_pixel(surface, px+1, py+0, color); + _set_pixel(surface, px+2, py+0, color); + + _set_pixel(surface, px+0, py+1, color); + _set_pixel(surface, px+1, py+1, color); + _set_pixel(surface, px+2, py+1, color); + + _set_pixel(surface, px+0, py+2, color); + _set_pixel(surface, px+1, py+2, color); + _set_pixel(surface, px+2, py+2, color); + x++; } } } -inline static void scr_render_hgr_line_color(struct scr_t *scr, int line, uint16_t line_base) { - - // Pre process the line. We put the color index in bytes to make it easier to handle them - - int pixels[280], x = 0; +inline static void scr_render_hgr_line_color(struct scr_t *scr, int line, uint16_t line_base, SDL_Surface *surface) { + uint32_t pixels[280], x = 0; for (int i = 0; i < 40; i++) { uint8_t c = scr->two->screen_hgr_data[line_base + i]; for (int j = 0; j < 7; j++) { if (c & (1 << j)) { if (x % 2 == 0) { if (c & 0x80) { - pixels[x] = 1; // Blue + pixels[x] = scr->hires_colors[1]; // Blue } else { - pixels[x] = 2; // Purple + pixels[x] = scr->hires_colors[2]; // Purple } } else { if (c & 0x80) { - pixels[x] = 4; // Red + pixels[x] = scr->hires_colors[4]; // Orange } else { - pixels[x] = 3; // Green + pixels[x] = scr->hires_colors[3]; // Green } } } else { - pixels[x] = 0; // Black + pixels[x] = scr->hires_colors[0]; // Black } x++; } } // Flip adject pixels to white - +#if 0 for (int i = 0; i < (280-1); i++) { if (pixels[i] && pixels[i+1]) { - pixels[i] = 5; // White + pixels[i] = scr->hires_colors[5]; // White } } +#endif // Now draw them for (x = 0; x < 280; x++) { - SDL_Rect dst; - dst.x = x * 3; - dst.y = line * 3; - dst.w = 3; - dst.h = 3; - - int c = pixels[x]; - SDL_SetRenderDrawColor(scr->renderer, hgr_colors[c].r, hgr_colors[c].g, hgr_colors[c].b, hgr_colors[c].a); - SDL_RenderFillRect(scr->renderer, &dst); + int px = x * 3, py = line * 3; + uint32_t color = pixels[x]; + _set_pixel(surface, px+0, py+0, color); + _set_pixel(surface, px+1, py+0, color); + _set_pixel(surface, px+2, py+0, color); + _set_pixel(surface, px+0, py+1, color); + _set_pixel(surface, px+1, py+1, color); + _set_pixel(surface, px+2, py+1, color); + _set_pixel(surface, px+0, py+2, color); + _set_pixel(surface, px+1, py+2, color); + _set_pixel(surface, px+2, py+2, color); } } @@ -266,12 +363,13 @@ inline static void scr_render_hgr_screen(struct scr_t *scr, bool flash) { // Render graphics int lines = (scr->two->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED) ? 160 : 192; uint16_t hgr_base = hgr_page_offsets[scr->two->screen_page]; + SDL_Surface *surface = SDL_GetWindowSurface(scr->window); for (int line = 0; line < lines; line++) { uint16_t line_base = hgr_base + hgr_line_offsets[line]; if (scr->color_scheme == EWM_SCR_COLOR_SCHEME_COLOR) { - scr_render_hgr_line_color(scr, line, line_base); + scr_render_hgr_line_color(scr, line, line_base, surface); } else { - scr_render_hgr_line_green(scr, line, line_base); + scr_render_hgr_line_green(scr, line, line_base, surface); } } @@ -285,11 +383,31 @@ inline static void scr_render_hgr_screen(struct scr_t *scr, bool flash) { } } -static int ewm_scr_init(struct scr_t *scr, struct ewm_two_t *two, SDL_Renderer *renderer) { +static int ewm_scr_init(struct scr_t *scr, struct ewm_two_t *two, SDL_Window *window, SDL_Renderer *renderer) { memset(scr, 0x00, sizeof(struct scr_t)); + scr->two = two; + scr->window = window; scr->renderer = renderer; - scr->chr = ewm_chr_create("rom/3410036.bin", EWM_CHR_ROM_TYPE_2716, renderer); + + // Cache colors for speed, to avoid calls to SDL_MapRGB + SDL_Surface *surface = SDL_GetWindowSurface(window); + if (scr->color_scheme == EWM_SCR_COLOR_SCHEME_MONOCHROME) { + scr->text_color = SDL_MapRGB(surface->format, 47, 249, 64); + } else { + scr->text_color = SDL_MapRGB(surface->format, 255, 255, 255); + } + for (int i = 0; i < 6; i++) { + scr->hires_colors[i] = SDL_MapRGB(surface->format, hires_colors[i].r, hires_colors[i].g, hires_colors[i].b); + } + for (int i = 0; i < 16; i++) { + scr->lores_colors_color[i] = SDL_MapRGB(surface->format, lores_colors_color[i].r, + lores_colors_color[i].g, lores_colors_color[i].b); + scr->lores_colors_green[i] = SDL_MapRGB(surface->format, lores_colors_green[i].r, + lores_colors_green[i].g, lores_colors_green[i].b); + } + + scr->chr = ewm_chr_create("rom/3410036.bin", EWM_CHR_ROM_TYPE_2716, renderer, scr->text_color); if (scr->chr == NULL) { fprintf(stderr, "[SCR] Failed to initialize character generator\n"); return -1; @@ -297,9 +415,9 @@ static int ewm_scr_init(struct scr_t *scr, struct ewm_two_t *two, SDL_Renderer * return 0; } -struct scr_t *ewm_scr_create(struct ewm_two_t *two, SDL_Renderer *renderer) { +struct scr_t *ewm_scr_create(struct ewm_two_t *two, SDL_Window *window, SDL_Renderer *renderer) { struct scr_t *scr = malloc(sizeof(struct scr_t)); - if (ewm_scr_init(scr, two, renderer) != 0) { + if (ewm_scr_init(scr, two, window, renderer) != 0) { free(scr); scr = NULL; } @@ -311,8 +429,7 @@ void ewm_scr_destroy(struct scr_t *scr) { } void ewm_scr_update(struct scr_t *scr, int phase, int fps) { - SDL_SetRenderDrawColor(scr->renderer, 0, 0, 0, 255); - SDL_RenderClear(scr->renderer); + SDL_FillRect(SDL_GetWindowSurface(scr->window), NULL, 0); switch (scr->two->screen_mode) { case EWM_A2P_SCREEN_MODE_TEXT: diff --git a/src/scr.h b/src/scr.h index 0534c55..adbe2a6 100644 --- a/src/scr.h +++ b/src/scr.h @@ -37,12 +37,18 @@ struct ewm_chr_t; struct scr_t { struct ewm_two_t *two; + SDL_Window *window; SDL_Renderer *renderer; struct ewm_chr_t *chr; int color_scheme; + + uint32_t text_color; + uint32_t lores_colors_color[16]; + uint32_t lores_colors_green[16]; + uint32_t hires_colors[6]; }; -struct scr_t *ewm_scr_create(struct ewm_two_t *two, SDL_Renderer *renderer); +struct scr_t *ewm_scr_create(struct ewm_two_t *two, SDL_Window *window, SDL_Renderer *renderer); void ewm_scr_destroy(struct scr_t *scr); void ewm_scr_update(struct scr_t *scr, int phase, int fps); void ewm_scr_set_color_scheme(struct scr_t *scr, int color_scheme); diff --git a/src/scr_test.c b/src/scr_test.c index e8363a1..3587f15 100644 --- a/src/scr_test.c +++ b/src/scr_test.c @@ -77,7 +77,8 @@ void hgr_full_refresh_test(struct scr_t *scr) { ewm_scr_update(scr, 0, 0); } -void test(struct scr_t *scr, char *name, test_setup_t test_setup, test_run_t test_run) { +void _test(struct scr_t *scr, char *name, test_setup_t test_setup, test_run_t test_run, int color_scheme) { + scr->color_scheme = color_scheme; test_setup(scr); Uint64 start = SDL_GetPerformanceCounter(); @@ -89,7 +90,15 @@ void test(struct scr_t *scr, char *name, test_setup_t test_setup, test_run_t tes double total = (double)((now - start)*1000) / SDL_GetPerformanceFrequency(); double per_screen = total / 1000.0; - printf("%-20s %.3f/refresh\n", name, per_screen); + printf("%-40s %-10s %.3f/refresh\n", name, + color_scheme == EWM_SCR_COLOR_SCHEME_MONOCHROME ? "green" : "color", per_screen); +} + +void test(struct scr_t *scr, char *name, test_setup_t test_setup, test_run_t test_run) { + sleep(1); + _test(scr, name, test_setup, test_run, EWM_SCR_COLOR_SCHEME_MONOCHROME); + sleep(1); + _test(scr, name, test_setup, test_run, EWM_SCR_COLOR_SCHEME_COLOR); } int main() { @@ -104,7 +113,9 @@ int main() { return 1; } - SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + + SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE); if (renderer == NULL) { fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError()); return 1; @@ -112,11 +123,9 @@ int main() { SDL_RenderSetLogicalSize(renderer, 280*3, 192*3); - sleep(3); // Is this ok? Seems to be needed to get the window on the screen - // Setup the CPU, Apple ][+ and it's screen. - struct ewm_two_t *two = ewm_two_create(EWM_TWO_TYPE_APPLE2PLUS, renderer, NULL); + struct ewm_two_t *two = ewm_two_create(EWM_TWO_TYPE_APPLE2PLUS, window, renderer, NULL); test(two->scr, "txt_full_refresh", txt_full_refresh_setup, txt_full_refresh_test); test(two->scr, "lgr_full_refresh", lgr_full_refresh_setup, lgr_full_refresh_test); diff --git a/src/tty.c b/src/tty.c index 1f7421e..8691aee 100644 --- a/src/tty.c +++ b/src/tty.c @@ -23,11 +23,13 @@ #include "chr.h" #include "tty.h" -struct ewm_tty_t *ewm_tty_create(SDL_Renderer *renderer) { +struct ewm_tty_t *ewm_tty_create(SDL_Window *window, SDL_Renderer *renderer) { struct ewm_tty_t *tty = malloc(sizeof(struct ewm_tty_t)); memset(tty, 0, sizeof(struct ewm_tty_t)); + tty->window = window; tty->renderer = renderer; - tty->chr = ewm_chr_create("rom/3410036.bin", EWM_CHR_ROM_TYPE_2716, renderer); + tty->text_color = SDL_MapRGB(SDL_GetWindowSurface(window)->format, 47, 249, 64); + tty->chr = ewm_chr_create("rom/3410036.bin", EWM_CHR_ROM_TYPE_2716, renderer, tty->text_color); ewm_tty_reset(tty); return tty; } @@ -37,16 +39,22 @@ void ewm_tty_destroy(struct ewm_tty_t *tty) { } static inline void ewm_tty_render_character(struct ewm_tty_t *tty, int row, int column, uint8_t c) { - // TODO Should we learn chr.c about the Apple1 character set instead of mapping it to the Apple ][+ one? - c += 0x80; - if (tty->chr->characters[c] != NULL) { + c += 0x80; // TODO Should we learn chr.c about the Apple1 character set instead of mapping it to the Apple ][+ one? + if (tty->chr->surfaces[c] != NULL) { + SDL_Rect src; + src.x = 0; + src.y = 0; + src.w = 21; + src.h = 24; + SDL_Rect dst; dst.x = column * 21; dst.y = row * 24; dst.w = 21; dst.h = 24; - SDL_SetTextureColorMod(tty->chr->characters[c], 0, 255, 0); - SDL_RenderCopy(tty->renderer, tty->chr->characters[c], NULL, &dst); + + SDL_SetSurfaceColorMod(tty->chr->surfaces[c], 47, 249, 64); + SDL_BlitSurface(tty->chr->surfaces[c], &src, SDL_GetWindowSurface(tty->window), &dst); } } diff --git a/src/tty.h b/src/tty.h index 129851d..a02703a 100644 --- a/src/tty.h +++ b/src/tty.h @@ -35,6 +35,7 @@ struct ewm_chr_t; struct ewm_tty_t { + SDL_Window *window; SDL_Renderer *renderer; struct ewm_chr_t *chr; bool screen_dirty; @@ -42,9 +43,10 @@ struct ewm_tty_t { int screen_cursor_row; int screen_cursor_column; int screen_cursor_blink; + uint32_t text_color; }; -struct ewm_tty_t *ewm_tty_create(SDL_Renderer *renderer); +struct ewm_tty_t *ewm_tty_create(SDL_Window *window, SDL_Renderer *renderer); void ewm_tty_destroy(struct ewm_tty_t *tty); void ewm_tty_write(struct ewm_tty_t *tty, uint8_t v); void ewm_tty_reset(struct ewm_tty_t *tty); diff --git a/src/two.c b/src/two.c index fd3e888..bb330ec 100644 --- a/src/two.c +++ b/src/two.c @@ -273,7 +273,7 @@ static void ewm_two_screen_hgr_write(struct cpu_t *cpu, struct mem_t *mem, uint1 two->screen_dirty = true; } -static int ewm_two_init(struct ewm_two_t *two, int type, SDL_Renderer *renderer, SDL_Joystick *joystick) { +static int ewm_two_init(struct ewm_two_t *two, int type, SDL_Window *window, SDL_Renderer *renderer, SDL_Joystick *joystick) { memset(two, 0, sizeof(struct ewm_two_t)); two->type = type; @@ -309,7 +309,7 @@ static int ewm_two_init(struct ewm_two_t *two, int type, SDL_Renderer *renderer, return -1; } - two->scr = ewm_scr_create(two, renderer); + two->scr = ewm_scr_create(two, window, renderer); if (two->scr == NULL) { fprintf(stderr, "[TWO] Could not create Screen\n"); return -1; @@ -337,9 +337,9 @@ static int ewm_two_init(struct ewm_two_t *two, int type, SDL_Renderer *renderer, return 0; } -struct ewm_two_t *ewm_two_create(int type, SDL_Renderer *renderer, SDL_Joystick *joystick) { +struct ewm_two_t *ewm_two_create(int type, SDL_Window *window, SDL_Renderer *renderer, SDL_Joystick *joystick) { struct ewm_two_t *two = malloc(sizeof(struct ewm_two_t)); - if (ewm_two_init(two, type, renderer, joystick) != 0) { + if (ewm_two_init(two, type, window, renderer, joystick) != 0) { free(two); two = NULL; } @@ -499,18 +499,17 @@ static bool ewm_two_step_cpu(struct ewm_two_t *two, int cycles) { } static void ewm_two_update_status_bar(struct ewm_two_t *two, double mhz) { - - SDL_Rect rect = { .x = 0, .y = (24*8*3), .w = (40*7*3), .h = (9*3) }; - SDL_SetRenderDrawColor(two->scr->renderer, 39, 39, 39, 0); - SDL_RenderFillRect(two->scr->renderer, &rect); - char s[41]; snprintf(s, 41, "%1.3f MHZ [1][2]", mhz); - // 1234567890123456789012345678901234567890 - for (int i = 0; i < 40; i++) { int c = s[i] + 0x80; - if (two->scr->chr->characters[c] != NULL) { + if (two->scr->chr->textures[c] != NULL) { + SDL_Rect src; + src.x = 0; + src.y = 0; + src.w = 21; + src.h = 24; + SDL_Rect dst; dst.x = i * 21; dst.y = 24 * 24 + 3; @@ -518,12 +517,13 @@ static void ewm_two_update_status_bar(struct ewm_two_t *two, double mhz) { dst.h = 24; if (two->dsk->on && ((i == 35 && two->dsk->drive == EWM_DSK_DRIVE1) || (i == 38 && two->dsk->drive == EWM_DSK_DRIVE2))) { - SDL_SetTextureColorMod(two->scr->chr->characters[c], 145, 193, 75); + SDL_SetSurfaceColorMod(two->scr->chr->surfaces[c], 145, 193, 75); + } else { - SDL_SetTextureColorMod(two->scr->chr->characters[c], 255, 0, 0); + SDL_SetSurfaceColorMod(two->scr->chr->surfaces[c], 255, 0, 0); } - SDL_RenderCopy(two->scr->renderer, two->scr->chr->characters[c], NULL, &dst); + SDL_BlitSurface(two->scr->chr->surfaces[c], &src, SDL_GetWindowSurface(two->scr->window), &dst); } } } @@ -632,14 +632,14 @@ int ewm_two_main(int argc, char **argv) { exit(1); } - SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + + SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE); if (renderer == NULL) { fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError()); exit(1); } - SDL_RenderSetLogicalSize(renderer, 280*3, 192*3); - // Print what renderer we got if (debug) { @@ -687,7 +687,7 @@ int ewm_two_main(int argc, char **argv) { // Create and configure the Apple II - struct ewm_two_t *two = ewm_two_create(EWM_TWO_TYPE_APPLE2PLUS, renderer, joystick); + struct ewm_two_t *two = ewm_two_create(EWM_TWO_TYPE_APPLE2PLUS, window, renderer, joystick); two->debug = debug; if (color) { diff --git a/src/two.h b/src/two.h index 58f15db..f25bcfd 100644 --- a/src/two.h +++ b/src/two.h @@ -101,7 +101,7 @@ struct ewm_two_t { bool debug; }; -struct ewm_two_t *ewm_two_create(int type, SDL_Renderer *renderer, SDL_Joystick *joystick); +struct ewm_two_t *ewm_two_create(int type, SDL_Window *window, SDL_Renderer *renderer, SDL_Joystick *joystick); void ewm_two_destroy(struct ewm_two_t *two); int ewm_two_load_disk(struct ewm_two_t *two, int drive, char *path);