Fixes #171 - Support software rendering in tty (#172)

This commit is contained in:
Stefan Arentz 2017-10-02 20:20:53 -04:00 committed by GitHub
parent 699072aa86
commit 9a517223e2
13 changed files with 270 additions and 42 deletions

1
.gitignore vendored
View File

@ -56,6 +56,7 @@ cpu_test
chr_test
mem_bench
cpu_bench
tty_test
*.bin
*.lst

View File

@ -42,7 +42,7 @@ ifeq ($(UNAME), Linux)
endif
EWM_EXECUTABLE=ewm
EWM_SOURCES=cpu.c ins.c pia.c mem.c ewm.c fmt.c two.c scr.c dsk.c chr.c alc.c one.c tty.c utl.c boo.c lua.c
EWM_SOURCES=cpu.c ins.c pia.c mem.c ewm.c fmt.c two.c scr.c dsk.c chr.c alc.c one.c tty.c utl.c boo.c lua.c sdl.c
EWM_OBJECTS=$(EWM_SOURCES:.c=.o)
EWM_LIBS=-lSDL2 $(LUA_LIBS)
@ -52,12 +52,12 @@ CPU_TEST_OBJECTS=$(CPU_TEST_SOURCES:.c=.o)
CPU_TEST_LIBS=$(LUA_LIBS)
SCR_TEST_EXECUTABLE=scr_test
SCR_TEST_SOURCES=cpu.c ins.c mem.c fmt.c two.c scr.c dsk.c chr.c alc.c utl.c scr_test.c lua.c
SCR_TEST_SOURCES=cpu.c ins.c mem.c fmt.c two.c scr.c dsk.c chr.c alc.c utl.c scr_test.c lua.c sdl.c
SCR_TEST_OBJECTS=$(SCR_TEST_SOURCES:.c=.o)
SCR_TEST_LIBS=-lSDL2 $(LUA_LIBS)
TTY_TEST_EXECUTABLE=tty_test
TTY_TEST_SOURCES=cpu.c ins.c mem.c fmt.c one.c tty.c pia.c chr.c utl.c tty_test.c lua.c
TTY_TEST_SOURCES=cpu.c ins.c mem.c fmt.c one.c tty.c pia.c chr.c utl.c tty_test.c lua.c sdl.c
TTY_TEST_OBJECTS=$(TTY_TEST_SOURCES:.c=.o)
TTY_TEST_LIBS=-lSDL2 $(LUA_LIBS)

View File

@ -25,6 +25,7 @@
#include <SDL2/SDL.h>
#include "tty.h"
#include "sdl.h"
#include "boo.h"
static char *menu[24] = {
@ -62,7 +63,8 @@ int ewm_boo_main(int argc, char **argv) {
return 1;
}
SDL_Window *window = SDL_CreateWindow("EWM v0.1 / Apple 1", 400, 60, 280*3, 192*3, SDL_WINDOW_SHOWN);
SDL_Window *window = SDL_CreateWindow("EWM v0.1 - Bootloader", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
280*3, 192*3, SDL_WINDOW_SHOWN);
if (window == NULL) {
fprintf(stderr, "Failed create window: %s\n", SDL_GetError());
return 1;
@ -74,7 +76,12 @@ int ewm_boo_main(int argc, char **argv) {
return 1;
}
SDL_RenderSetLogicalSize(renderer, 280*3, 192*3);
if (ewm_sdl_check_renderer(renderer) != 0) {
fprintf(stderr, "ewm: boo: unsupported renderer\n");
return 1;
}
SDL_RenderSetLogicalSize(renderer, 280, 192);
// We only need a tty to display the menu
@ -125,7 +132,6 @@ int ewm_boo_main(int argc, char **argv) {
SDL_SetRenderDrawColor(tty->renderer, 0, 0, 0, 255);
SDL_RenderClear(tty->renderer);
for (int i = 0; i < 24; i++) {
char *p = (char*) tty->screen_buffer;
p += (i * 40);
@ -135,12 +141,15 @@ int ewm_boo_main(int argc, char **argv) {
tty->screen_cursor_column = 34;
tty->screen_cursor_row = 9;
//strcpy((char*) tty->screen_buffer, "1) APPLE 1 2) REPLICA 1 3) APPLE ][+");
ewm_tty_refresh(tty, phase, EWM_BOO_FPS);
tty->screen_dirty = false;
SDL_Texture *texture = SDL_CreateTextureFromSurface(tty->renderer, tty->surface);
if (texture != NULL) {
SDL_RenderCopy(tty->renderer, texture, NULL, NULL);
SDL_DestroyTexture(texture);
}
SDL_RenderPresent(tty->renderer);
}

View File

@ -31,6 +31,7 @@
#include <SDL2/SDL.h>
#include "sdl.h"
#include "chr.h"
static int _load_rom_data(char *rom_path, uint8_t rom_data[2048]) {
@ -96,39 +97,98 @@ static SDL_Texture *_generate_texture(SDL_Renderer *renderer, uint8_t rom_data[2
return texture;
}
static uint32_t *_generate_bitmap(struct ewm_chr_t *chr, uint8_t rom_data[2048], int c, bool inverse) {
uint32_t *pixels = (uint32_t*) malloc(4 * ewm_chr_width(chr) * ewm_chr_height(chr));
if (pixels != NULL) {
memset(pixels, 0x00, 4 * ewm_chr_width(chr) * ewm_chr_height(chr));
uint8_t character_data[8];
for (int i = 0; i < 8; i++) {
character_data[i] = rom_data[(c * 8) + i + 1];
if (inverse) {
character_data[i] ^= 0xff;
}
}
uint32_t *p = pixels;
for (int y = 0; y < 8; y++) {
for (int x = 6; x >= 0; x--) {
if (character_data[y] & (1 << x)) {
*p++ = chr->green;
} else {
*p++ = 0x00000000;
}
}
}
}
return pixels;
}
static int ewm_chr_init(struct ewm_chr_t *chr, char *rom_path, int rom_type, SDL_Renderer *renderer) {
if (rom_type != EWM_CHR_ROM_TYPE_2716) {
return -1;
}
memset(chr, 0x00, sizeof(struct ewm_chr_t));
chr->renderer = renderer;
chr->green = ewm_sdl_green(renderer);
uint8_t rom_data[2048];
if (_load_rom_data(rom_path, rom_data) != 0) {
return -1;
}
// Bitmaps
// Normal Text
for (int c = 0; c < 32; c++) {
chr->characters[0xc0 + c] = _generate_texture(renderer, rom_data, c, false);
chr->bitmaps[0xc0 + c] = _generate_bitmap(chr, rom_data, c, false);
}
for (int c = 32; c < 64; c++) {
chr->characters[0xa0 + (c-32)] = _generate_texture(renderer, rom_data, c, false);
chr->bitmaps[0xa0 + (c-32)] = _generate_bitmap(chr, rom_data, c, false);
}
// Inverse Text
for (int c = 0; c < 32; c++) {
chr->characters[0x00 + c] = _generate_texture(renderer, rom_data, c, true);
chr->bitmaps[0x00 + c] = _generate_bitmap(chr, rom_data, c, true);
}
for (int c = 32; c < 64; c++) {
chr->characters[0x20 + (c-32)] = _generate_texture(renderer, rom_data, c, true);
chr->bitmaps[0x20 + (c-32)] = _generate_bitmap(chr, rom_data, c, true);
}
// 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->bitmaps[0x40 + c] = _generate_bitmap(chr, rom_data, c, true);
}
for (int c = 32; c < 64; c++) {
chr->characters[0x60 + (c-32)] = _generate_texture(renderer, rom_data, c, true);
chr->bitmaps[0x60 + (c-32)] = _generate_bitmap(chr, rom_data, c, true);
}
// Textures
// Normal Text
for (int c = 0; c < 32; c++) {
chr->textures[0xc0 + c] = _generate_texture(renderer, rom_data, c, false);
}
for (int c = 32; c < 64; c++) {
chr->textures[0xa0 + (c-32)] = _generate_texture(renderer, rom_data, c, false);
}
// Inverse Text
for (int c = 0; c < 32; c++) {
chr->textures[0x00 + c] = _generate_texture(renderer, rom_data, c, true);
}
for (int c = 32; c < 64; c++) {
chr->textures[0x20 + (c-32)] = _generate_texture(renderer, rom_data, c, true);
}
// TODO Flashing - Currently simply rendered as inverse
for (int c = 0; c < 32; c++) {
chr->textures[0x40 + c] = _generate_texture(renderer, rom_data, c, true);
}
for (int c = 32; c < 64; c++) {
chr->textures[0x60 + (c-32)] = _generate_texture(renderer, rom_data, c, true);
}
return 0;
@ -144,13 +204,10 @@ 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);
if (chr == NULL) {
printf("Failed to load character ROM %s\n", "rom/3410036.bin");
exit(1);
}
return 0;
int ewm_chr_width(struct ewm_chr_t* chr) {
return 7; // TODO Should be based on the ROM type?
}
int ewm_chr_height(struct ewm_chr_t* chr) {
return 8; // TODO Should be based on the ROM type?
}
#endif

View File

@ -28,9 +28,14 @@
#define EWM_CHR_ROM_TYPE_2716 (2716)
struct ewm_chr_t {
SDL_Texture* characters[256];
SDL_Renderer *renderer;
SDL_Texture *textures[256];
uint32_t *bitmaps[256];
uint32_t green;
};
struct ewm_chr_t* ewm_chr_create(char *rom_path, int rom_type, SDL_Renderer *renderer);
int ewm_chr_width(struct ewm_chr_t* chr);
int ewm_chr_height(struct ewm_chr_t* chr);
#endif

View File

@ -26,6 +26,7 @@
#include <SDL2/SDL.h>
#include "sdl.h"
#include "cpu.h"
#include "mem.h"
#include "pia.h"
@ -253,7 +254,8 @@ int ewm_one_main(int argc, char **argv) {
return 1;
}
SDL_Window *window = SDL_CreateWindow("EWM v0.1 / Apple 1", 400, 60, 280*3, 192*3, SDL_WINDOW_SHOWN);
SDL_Window *window = SDL_CreateWindow("EWM v0.1 - Apple 1", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
280*3, 192*3, SDL_WINDOW_SHOWN);
if (window == NULL) {
fprintf(stderr, "Failed create window: %s\n", SDL_GetError());
return 1;
@ -265,7 +267,12 @@ int ewm_one_main(int argc, char **argv) {
return 1;
}
SDL_RenderSetLogicalSize(renderer, 280*3, 192*3);
if (ewm_sdl_check_renderer(renderer) != 0) {
fprintf(stderr, "ewm: boo: unsupported renderer\n");
return 1;
}
SDL_RenderSetLogicalSize(renderer, 280, 192);
// Create the machine
@ -314,6 +321,12 @@ int ewm_one_main(int argc, char **argv) {
ewm_tty_refresh(one->tty, phase, EWM_ONE_FPS);
one->tty->screen_dirty = false;
SDL_Texture *texture = SDL_CreateTextureFromSurface(one->tty->renderer, one->tty->surface);
if (texture != NULL) {
SDL_RenderCopy(one->tty->renderer, texture, NULL, NULL);
SDL_DestroyTexture(texture);
}
SDL_RenderPresent(one->tty->renderer);
}

View File

@ -41,7 +41,7 @@ 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->cpu->ram[((txt_line_offsets[row] + base) + column)];
if (scr->chr->characters[c] != NULL) {
if (scr->chr->textures[c] != NULL) {
SDL_Rect dst;
dst.x = column * 21;
dst.y = row * 24;
@ -61,12 +61,12 @@ 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_SetTextureColorMod(scr->chr->textures[c], 0, 255, 0);
} else {
SDL_SetTextureColorMod(scr->chr->characters[c], 255, 255, 255);
SDL_SetTextureColorMod(scr->chr->textures[c], 255, 255, 255);
}
SDL_RenderCopy(scr->renderer, scr->chr->characters[c], NULL, &dst);
SDL_RenderCopy(scr->renderer, scr->chr->textures[c], NULL, &dst);
}
}

72
src/sdl.c Normal file
View File

@ -0,0 +1,72 @@
// 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 <stdio.h>
#include <SDL2/SDL.h>
int ewm_sdl_pixel_format(SDL_Renderer *renderer) {
SDL_RendererInfo info;
if (SDL_GetRendererInfo(renderer, &info) != 0) {
return -1;
}
for (Uint32 i = 0; i < info.num_texture_formats; i++) {
int format = info.texture_formats[i];
if (format == SDL_PIXELFORMAT_ARGB8888 || format == SDL_PIXELFORMAT_RGBA8888 || format == SDL_PIXELFORMAT_RGB888) {
return format;
}
}
return -1;
}
int ewm_sdl_check_renderer(SDL_Renderer *renderer) {
SDL_RendererInfo info;
if (SDL_GetRendererInfo(renderer, &info) != 0) {
printf("ewm: sdl: cannot get renderer info: %s\n", SDL_GetError());
return -1;
}
if ((info.flags & SDL_RENDERER_ACCELERATED) == 0) {
printf("ewm: sdl: require accelerated renderer\n");
return -1;
}
if (ewm_sdl_pixel_format(renderer) == -1) {
printf("ewm: sdl: cannot find supported pixel format (ARGB888, RGBA8888, RGB888)\n");
return -1;
}
return 0;
}
uint32_t ewm_sdl_green(SDL_Renderer *renderer) {
switch (ewm_sdl_pixel_format(renderer)) {
case SDL_PIXELFORMAT_RGBA8888:
return 0x00ff00ff;
case SDL_PIXELFORMAT_ARGB8888:
return 0xff00ff00;
case SDL_PIXELFORMAT_RGB888:
return 0x00ff0000;
}
return 0xffffff;
}

32
src/sdl.h Normal file
View File

@ -0,0 +1,32 @@
// 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.
#ifndef EWM_SDL
#define EWM_SDL
#include <SDL2/SDL.h>
int ewm_sdl_pixel_format(SDL_Renderer *renderer);
int ewm_sdl_check_renderer(SDL_Renderer *renderer);
uint32_t ewm_sdl_green(SDL_Renderer *renderer);
#endif // EWM_SDL

View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include "chr.h"
#include "sdl.h"
#include "tty.h"
struct ewm_tty_t *ewm_tty_create(SDL_Renderer *renderer) {
@ -28,6 +29,12 @@ struct ewm_tty_t *ewm_tty_create(SDL_Renderer *renderer) {
memset(tty, 0, sizeof(struct ewm_tty_t));
tty->renderer = renderer;
tty->chr = ewm_chr_create("rom/3410036.bin", EWM_CHR_ROM_TYPE_2716, renderer);
tty->pixels = malloc(4 * EWM_ONE_TTY_COLUMNS * ewm_chr_width(tty->chr) * EWM_ONE_TTY_ROWS * ewm_chr_height(tty->chr));
tty->surface = SDL_CreateRGBSurfaceWithFormatFrom(tty->pixels, EWM_ONE_TTY_COLUMNS * ewm_chr_width(tty->chr),
EWM_ONE_TTY_ROWS * ewm_chr_height(tty->chr), 32, 4 * EWM_ONE_TTY_COLUMNS * ewm_chr_width(tty->chr),
ewm_sdl_pixel_format(renderer));
ewm_tty_reset(tty);
return tty;
}
@ -36,19 +43,36 @@ void ewm_tty_destroy(struct ewm_tty_t *tty) {
// TODO
}
#if 0
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) {
SDL_Rect dst;
dst.x = column * 21;
dst.y = row * 24;
dst.w = 21;
dst.h = 24;
dst.x = column * 7;
dst.y = row * 8;
dst.w = 7;
dst.h = 8;
SDL_SetTextureColorMod(tty->chr->characters[c], 0, 255, 0);
SDL_RenderCopy(tty->renderer, tty->chr->characters[c], NULL, &dst);
}
}
#endif
// Take one - get something on the screen. Very inefficient to do it char-by-char, but good baseline.
static inline void ewm_tty_render_character(struct ewm_tty_t *tty, int row, int column, uint8_t c) {
c += 0x80; // TODO This should not be there really
uint32_t *src = tty->chr->bitmaps[c];
if (src != NULL) {
uint32_t *dst = tty->pixels + ((40 * 7 * 8) * row) + (7 * column);
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 7; x++) {
*dst++ = *src++;
}
dst += (40 * 7) - 7;
}
}
}
static void tty_scroll_up(struct ewm_tty_t *tty) {
memmove(tty->screen_buffer, &tty->screen_buffer[EWM_ONE_TTY_COLUMNS], (EWM_ONE_TTY_ROWS-1) * EWM_ONE_TTY_COLUMNS);
@ -84,6 +108,7 @@ void ewm_tty_reset(struct ewm_tty_t *tty) {
tty->screen_buffer[(row * EWM_ONE_TTY_COLUMNS) + column] = 0x00;
}
}
tty->screen_cursor_row = 0;
tty->screen_cursor_column = 0;
tty->screen_dirty = true;
@ -101,6 +126,8 @@ void ewm_tty_refresh(struct ewm_tty_t *tty, uint32_t phase, uint32_t fps) {
}
if (tty->screen_cursor_blink) {
ewm_tty_render_character(tty, tty->screen_cursor_row, tty->screen_cursor_column, EWM_ONE_TTY_CURSOR);
ewm_tty_render_character(tty, tty->screen_cursor_row, tty->screen_cursor_column, EWM_ONE_TTY_CURSOR_ON);
} else {
ewm_tty_render_character(tty, tty->screen_cursor_row, tty->screen_cursor_column, EWM_ONE_TTY_CURSOR_OFF);
}
}

View File

@ -30,7 +30,8 @@
#define EWM_ONE_TTY_ROWS 24
#define EWM_ONE_TTY_COLUMNS 40
#define EWM_ONE_TTY_CURSOR '@'
#define EWM_ONE_TTY_CURSOR_ON '@'
#define EWM_ONE_TTY_CURSOR_OFF ' '
struct ewm_chr_t;
@ -42,6 +43,9 @@ struct ewm_tty_t {
int screen_cursor_row;
int screen_cursor_column;
int screen_cursor_blink;
uint32_t *pixels;
SDL_Surface *surface;
};
struct ewm_tty_t *ewm_tty_create(SDL_Renderer *renderer);

View File

@ -16,7 +16,15 @@ void test(struct ewm_tty_t *tty) {
for (int i = 0; i < 1000; i++) {
SDL_SetRenderDrawColor(tty->renderer, 0, 0, 0, 255);
SDL_RenderClear(tty->renderer);
ewm_tty_refresh(tty, 1, EWM_ONE_FPS);
SDL_Texture *texture = SDL_CreateTextureFromSurface(tty->renderer, tty->surface);
if (texture != NULL) {
SDL_RenderCopy(tty->renderer, texture, NULL, NULL);
SDL_DestroyTexture(texture);
}
SDL_RenderPresent(tty->renderer);
}
Uint64 now = SDL_GetPerformanceCounter();
@ -44,7 +52,7 @@ int main() {
return 1;
}
SDL_RenderSetLogicalSize(renderer, 280*3, 192*3);
SDL_RenderSetLogicalSize(renderer, 280, 192);
sleep(3);

View File

@ -629,7 +629,7 @@ static void ewm_two_update_status_bar(struct ewm_two_t *two, double mhz) {
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 dst;
dst.x = i * 21;
dst.y = 24 * 24 + 3;
@ -637,12 +637,12 @@ 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_SetTextureColorMod(two->scr->chr->textures[c], 145, 193, 75);
} else {
SDL_SetTextureColorMod(two->scr->chr->characters[c], 255, 0, 0);
SDL_SetTextureColorMod(two->scr->chr->textures[c], 255, 0, 0);
}
SDL_RenderCopy(two->scr->renderer, two->scr->chr->characters[c], NULL, &dst);
SDL_RenderCopy(two->scr->renderer, two->scr->chr->textures[c], NULL, &dst);
}
}
}