Fixes #120 Implement a software renderer

This commit is contained in:
Stefan Arentz 2017-01-07 08:52:56 -05:00
parent c68fc356c6
commit f94cb5c954
14 changed files with 404 additions and 158 deletions

View File

@ -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 $@

View File

@ -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

View File

@ -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);

View File

@ -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

59
src/chr_test.c Normal file
View File

@ -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 <stdio.h>
#include <unistd.h>
#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;
}

View File

@ -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;
}

View File

@ -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);

273
src/scr.c
View File

@ -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:

View File

@ -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);

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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) {

View File

@ -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);