mirror of
https://github.com/mauiaaron/apple2.git
synced 2024-06-01 13:41:28 +00:00
Squashed commit of the following:
CPU speed animation touch-ups, and enable building for desktop Rename/shuffle animation declarations and code Refactor backend video system to be a dynamically initialized module Basic CPU speed texture animation works on desktop Linux and Android Use static pixel buffers to avoid malloc/free churn Improve CPU animations First cut at CPU speed message animation Refactor some of the classic interface functions to be potentially reusable elsewhere
This commit is contained in:
parent
358541b8cc
commit
af42dc36b2
|
@ -9,11 +9,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include "common.h"
|
||||
#include "video/renderer.h"
|
||||
#include "androidkeys.h"
|
||||
|
||||
#include <jni.h>
|
||||
#include <math.h>
|
||||
|
||||
static bool nativePaused = false;
|
||||
|
||||
#if TESTING
|
||||
|
@ -56,22 +57,22 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jobje
|
|||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeGraphicsChanged(JNIEnv *env, jobject obj, jint width, jint height) {
|
||||
LOG("%s", "native graphicsChanged...");
|
||||
video_driver_reshape(width, height);
|
||||
video_backend->reshape(width, height);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeGraphicsInitialized(JNIEnv *env, jobject obj, jint width, jint height) {
|
||||
LOG("%s", "native graphicsInitialized...");
|
||||
video_driver_reshape(width, height);
|
||||
video_backend->reshape(width, height);
|
||||
|
||||
#if TESTING
|
||||
_run_tests();
|
||||
#else
|
||||
static bool graphicsPreviouslyInitialized = false;
|
||||
if (graphicsPreviouslyInitialized) {
|
||||
video_driver_shutdown();
|
||||
video_backend->shutdown();
|
||||
}
|
||||
graphicsPreviouslyInitialized = true;
|
||||
video_driver_init((void *)0);
|
||||
video_backend->init((void *)0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -118,7 +119,7 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeRender(JNIEnv *env, jobject
|
|||
|
||||
extern volatile bool _vid_dirty;
|
||||
_vid_dirty = true;
|
||||
video_driver_render();
|
||||
video_backend->render();
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeReboot(JNIEnv *env, jobject obj) {
|
||||
|
@ -160,17 +161,23 @@ jboolean Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnTouch(JNIEnv *env, jo
|
|||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeIncreaseCPUSpeed(JNIEnv *env, jobject obj) {
|
||||
pthread_mutex_lock(&interface_mutex);
|
||||
|
||||
if (cpu_scale_factor > 1.0) {
|
||||
cpu_scale_factor += 0.25;
|
||||
int percent_scale = (int)round(cpu_scale_factor * 100.0);
|
||||
if (percent_scale >= 100) {
|
||||
percent_scale += 25;
|
||||
} else {
|
||||
cpu_scale_factor += 0.05;
|
||||
percent_scale += 5;
|
||||
}
|
||||
cpu_scale_factor = percent_scale/100.0;
|
||||
|
||||
if (cpu_scale_factor > CPU_SCALE_FASTEST) {
|
||||
cpu_scale_factor = CPU_SCALE_FASTEST;
|
||||
}
|
||||
|
||||
//video_driver_animate_speedscale();
|
||||
LOG("native set emulation percentage to %f", cpu_scale_factor);
|
||||
|
||||
if (video_animation_show_cpuspeed) {
|
||||
video_animation_show_cpuspeed();
|
||||
}
|
||||
|
||||
#warning HACK TODO FIXME ... refactor timing stuff
|
||||
timing_toggle_cpu_speed();
|
||||
|
@ -182,17 +189,28 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeIncreaseCPUSpeed(JNIEnv *en
|
|||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeDecreaseCPUSpeed(JNIEnv *env, jobject obj) {
|
||||
pthread_mutex_lock(&interface_mutex);
|
||||
|
||||
if (cpu_scale_factor > 1.0) {
|
||||
cpu_scale_factor -= 0.25;
|
||||
int percent_scale = (int)round(cpu_scale_factor * 100.0);
|
||||
if (cpu_scale_factor == CPU_SCALE_FASTEST) {
|
||||
cpu_scale_factor = CPU_SCALE_FASTEST0;
|
||||
percent_scale = (int)round(cpu_scale_factor * 100);
|
||||
} else {
|
||||
cpu_scale_factor -= 0.05;
|
||||
if (percent_scale > 100) {
|
||||
percent_scale -= 25;
|
||||
} else {
|
||||
percent_scale -= 5;
|
||||
}
|
||||
}
|
||||
cpu_scale_factor = percent_scale/100.0;
|
||||
|
||||
if (cpu_scale_factor < CPU_SCALE_SLOWEST) {
|
||||
cpu_scale_factor = CPU_SCALE_SLOWEST;
|
||||
}
|
||||
|
||||
//video_driver_animate_speedscale();
|
||||
LOG("native set emulation percentage to %f", cpu_scale_factor);
|
||||
|
||||
if (video_animation_show_cpuspeed) {
|
||||
video_animation_show_cpuspeed();
|
||||
}
|
||||
|
||||
#warning HACK TODO FIXME ... refactor timing stuff
|
||||
timing_toggle_cpu_speed();
|
||||
|
|
|
@ -11,6 +11,8 @@ APPLE2_ARM_SRC := \
|
|||
|
||||
APPLE2_VIDEO_SRC = \
|
||||
$(APPLE2_SRC_PATH)/video/glvideo.c \
|
||||
$(APPLE2_SRC_PATH)/video/glanimation.c \
|
||||
$(APPLE2_SRC_PATH)/video/glcpuanim.c \
|
||||
$(APPLE2_SRC_PATH)/video/gltouchjoy.c \
|
||||
$(APPLE2_SRC_PATH)/video_util/matrixUtil.c \
|
||||
$(APPLE2_SRC_PATH)/video_util/modelUtil.c \
|
||||
|
|
|
@ -37,6 +37,8 @@ INTERFACE_CLASSIC_SRC = \
|
|||
VIDEO_SRC = \
|
||||
src/video/xvideo.c \
|
||||
src/video/glvideo.c \
|
||||
src/video/glanimation.c \
|
||||
src/video/glcpuanim.c \
|
||||
src/video/glutinput.c \
|
||||
src/video_util/matrixUtil.c \
|
||||
src/video_util/modelUtil.c \
|
||||
|
|
|
@ -170,7 +170,7 @@ AC_ARG_ENABLE([opengl], AS_HELP_STRING([--disable-opengl], [Disable OpenGL video
|
|||
opengl_supported='yes'
|
||||
AC_DEFINE(VIDEO_OPENGL, 1, [Use OpenGL])
|
||||
AC_DEFINE(USE_GLUT, 1, [Use GLUT library])
|
||||
VIDEO_O="src/video/glvideo.o src/video/glutinput.o src/video_util/matrixUtil.o src/video_util/modelUtil.o src/video_util/sourceUtil.o src/video_util/vectorUtil.o"
|
||||
VIDEO_O="src/video/glvideo.o src/video/glanimation.o src/video/glcpuanim.o src/video/glutinput.o src/video_util/matrixUtil.o src/video_util/modelUtil.o src/video_util/sourceUtil.o src/video_util/vectorUtil.o"
|
||||
AC_MSG_RESULT([Building emulator with OpenGL support, w00t!])
|
||||
], [
|
||||
AC_MSG_WARN([Did not find OpenGL GLEW library...])
|
||||
|
|
227
src/display.c
227
src/display.c
|
@ -15,7 +15,8 @@
|
|||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "video/renderer.h"
|
||||
|
||||
#define SCANSTEP SCANWIDTH-12
|
||||
|
||||
#define DYNAMIC_SZ 11 // 7 pixels (as bytes) + 2pre + 2post
|
||||
|
||||
|
@ -23,10 +24,12 @@
|
|||
static uint8_t vga_mem_page_0[SCANWIDTH*SCANHEIGHT];
|
||||
static uint8_t vga_mem_page_1[SCANWIDTH*SCANHEIGHT];
|
||||
|
||||
A2Color colormap[256] = { { 0 } };
|
||||
A2Color_s colormap[256] = { { 0 } };
|
||||
video_backend_s *video_backend = NULL;
|
||||
|
||||
uint8_t video__wider_font[0x8000];
|
||||
uint8_t video__font[0x4000];
|
||||
static uint8_t video__wider_font[0x8000];
|
||||
static uint8_t video__font[0x4000];
|
||||
static uint8_t video__int_font[3][0x4000]; // interface font
|
||||
|
||||
// Precalculated framebuffer offsets given VM addr
|
||||
unsigned int video__screen_addresses[8192];
|
||||
|
@ -41,11 +44,6 @@ uint8_t video__hires_odd[0x800];
|
|||
uint8_t video__dhires1[256];
|
||||
uint8_t video__dhires2[256];
|
||||
|
||||
#ifdef INTERFACE_CLASSIC
|
||||
// Interface font
|
||||
static uint8_t video__int_font[3][0x4000];
|
||||
#endif
|
||||
|
||||
int video__current_page; // current visual page
|
||||
int video__strictcolors = 1;// refactor : should be static
|
||||
|
||||
|
@ -493,8 +491,7 @@ void video_loadfont(int first, int quantity, const uint8_t *data, int mode) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef INTERFACE_CLASSIC
|
||||
void video_loadfont_int(int first, int quantity, const uint8_t *data) {
|
||||
static void video_loadfont_int(int first, int quantity, const uint8_t *data) {
|
||||
unsigned int i = quantity * 8;
|
||||
while (i--) {
|
||||
unsigned int j = 8;
|
||||
|
@ -512,10 +509,9 @@ void video_loadfont_int(int first, int quantity, const uint8_t *data) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Plotting routines
|
||||
// lores/char plotting routines
|
||||
|
||||
static inline void _plot_char40(uint8_t **d, uint8_t **s) {
|
||||
*((uint32_t *)(*d)) = *((uint32_t *)(*s));
|
||||
|
@ -536,19 +532,19 @@ static inline void _plot_char40(uint8_t **d, uint8_t **s) {
|
|||
*d += SCANSTEP, *s += 4;
|
||||
}
|
||||
|
||||
static inline void _plot_char80(uint8_t **d, uint8_t **s) {
|
||||
static inline void _plot_char80(uint8_t **d, uint8_t **s, const unsigned int fb_width) {
|
||||
*((uint32_t *)(*d)) = *((uint32_t *)(*s));
|
||||
*d += 4, *s += 4;
|
||||
*((uint16_t *)(*d)) = *((uint16_t *)(*s));
|
||||
*d += 2, *s += 2;
|
||||
*((uint8_t *)(*d)) = *((uint8_t *)(*s));
|
||||
*d += SCANWIDTH-6, *s -= 6;
|
||||
*d += fb_width-6, *s -= 6;
|
||||
*((uint32_t *)(*d)) = *((uint32_t *)(*s));
|
||||
*d += 4, *s += 4;
|
||||
*((uint16_t *)(*d)) = *((uint16_t *)(*s));
|
||||
*d += 2, *s += 2;
|
||||
*((uint8_t *)(*d)) = *((uint8_t *)(*s));
|
||||
*d += SCANWIDTH-6, *s += 2;
|
||||
*d += fb_width-6, *s += 2;
|
||||
}
|
||||
|
||||
static inline void _plot_lores(uint8_t **d, const uint32_t val) {
|
||||
|
@ -569,27 +565,6 @@ static inline void _plot_lores(uint8_t **d, const uint32_t val) {
|
|||
*((uint16_t *)(*d)) = (uint16_t)(val & 0xffff);
|
||||
}
|
||||
|
||||
#ifdef INTERFACE_CLASSIC
|
||||
void video_plotchar( int x, int y, int scheme, uint8_t c ) {
|
||||
_vid_dirty = true;
|
||||
uint8_t *d;
|
||||
uint8_t *s;
|
||||
|
||||
unsigned int off = y * SCANWIDTH * 16 + x * 7 + 4;
|
||||
s = video__int_font[scheme] + c * 64;
|
||||
d = video__fb1 + off;
|
||||
|
||||
_plot_char80(&d,&s);
|
||||
_plot_char80(&d,&s);
|
||||
_plot_char80(&d,&s);
|
||||
_plot_char80(&d,&s);
|
||||
_plot_char80(&d,&s);
|
||||
_plot_char80(&d,&s);
|
||||
_plot_char80(&d,&s);
|
||||
_plot_char80(&d,&s);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void _plot_character(const unsigned int font_off, uint8_t *fb_ptr) {
|
||||
_vid_dirty = true;
|
||||
uint8_t *font_ptr = video__wider_font+font_off;
|
||||
|
@ -616,14 +591,14 @@ static inline void _plot_character1(uint16_t ea, uint8_t b)
|
|||
static inline void _plot_80character(const unsigned int font_off, uint8_t *fb_ptr) {
|
||||
_vid_dirty = true;
|
||||
uint8_t *font_ptr = video__font+font_off;
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr, SCANWIDTH);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr, SCANWIDTH);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr, SCANWIDTH);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr, SCANWIDTH);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr, SCANWIDTH);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr, SCANWIDTH);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr, SCANWIDTH);
|
||||
_plot_char80(/*dst*/&fb_ptr, /*src*/&font_ptr, SCANWIDTH);
|
||||
}
|
||||
|
||||
// FIXME TODO NOTE : dup'ing work here?
|
||||
|
@ -743,6 +718,162 @@ GLUE_C_WRITE(video__write_2e_text1_mixed)
|
|||
DRAW_MIXED(1, SS_RAMWRT);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// interface/messages plotting
|
||||
|
||||
void video_load_interface_fonts(void) {
|
||||
video_loadfont_int(0x00,0x40,ucase_glyphs);
|
||||
video_loadfont_int(0x40,0x20,ucase_glyphs);
|
||||
video_loadfont_int(0x60,0x20,lcase_glyphs);
|
||||
video_loadfont_int(0x80,0x40,ucase_glyphs);
|
||||
video_loadfont_int(0xC0,0x20,ucase_glyphs);
|
||||
video_loadfont_int(0xE0,0x20,lcase_glyphs);
|
||||
video_loadfont_int(0x80,11,interface_glyphs);
|
||||
video_loadfont_int(MOUSETEXT_BEGIN,0x20,mousetext_glyphs);
|
||||
}
|
||||
|
||||
// Classic interface and messages
|
||||
void video_plotchar_fb(uint8_t *fb, int fb_width, int x, int y, int scheme, uint8_t c) {
|
||||
_vid_dirty = true;
|
||||
|
||||
unsigned int off = y * fb_width * 16 + x * 7 + 4;
|
||||
uint8_t *dst = fb + off;
|
||||
uint8_t *src = video__int_font[scheme] + c * 64;
|
||||
|
||||
_plot_char80(&dst, &src, fb_width);
|
||||
_plot_char80(&dst, &src, fb_width);
|
||||
_plot_char80(&dst, &src, fb_width);
|
||||
_plot_char80(&dst, &src, fb_width);
|
||||
_plot_char80(&dst, &src, fb_width);
|
||||
_plot_char80(&dst, &src, fb_width);
|
||||
_plot_char80(&dst, &src, fb_width);
|
||||
_plot_char80(&dst, &src, fb_width);
|
||||
}
|
||||
|
||||
void video_plotchar(int x, int y, int scheme, uint8_t c) {
|
||||
video_plotchar_fb(video__fb1, SCANWIDTH, x, y, scheme, c);
|
||||
}
|
||||
|
||||
void video_interface_print_fb(uint8_t *fb, int fb_width, int x, int y, int cs, const char *s) {
|
||||
for (; *s; x++, s++) {
|
||||
video_plotchar_fb(fb, fb_width, x, y, cs, *s);
|
||||
}
|
||||
}
|
||||
|
||||
void video_interface_print(int x, int y, int cs, const char *s) {
|
||||
video_interface_print_fb(video__fb1, SCANWIDTH, x, y, cs, s);
|
||||
}
|
||||
|
||||
#define IsGraphic(c) ((c) == '|' || (((unsigned char)c) >= 0x80 && ((unsigned char)c) <= 0x8A))
|
||||
#define IsInside(x,y) ((x) >= 0 && (x) <= xlen-1 && (y) >= 0 && (y) <= ylen-1)
|
||||
|
||||
static void _convert_screen_graphics(char *screen, const int x, const int y, const int xlen, const int ylen) {
|
||||
static char map[11][3][4] ={ { "...",
|
||||
".||",
|
||||
".|." },
|
||||
|
||||
{ "...",
|
||||
"||.",
|
||||
".|." },
|
||||
|
||||
{ ".|.",
|
||||
".||",
|
||||
"..." },
|
||||
|
||||
{ ".|.",
|
||||
"||.",
|
||||
"..." },
|
||||
|
||||
{ "~|~",
|
||||
".|.",
|
||||
"~|~" },
|
||||
|
||||
{ "~.~",
|
||||
"|||",
|
||||
"~.~" },
|
||||
|
||||
{ ".|.",
|
||||
".||",
|
||||
".|." },
|
||||
|
||||
{ ".|.",
|
||||
"||.",
|
||||
".|." },
|
||||
|
||||
{ "...",
|
||||
"|||",
|
||||
".|." },
|
||||
|
||||
{ ".|.",
|
||||
"|||",
|
||||
"..." },
|
||||
|
||||
{ ".|.",
|
||||
"|||",
|
||||
".|." } };
|
||||
|
||||
bool found_glyph = false;
|
||||
int k = 10;
|
||||
for (; k >= 0; k--) {
|
||||
found_glyph = true;
|
||||
|
||||
for (int yy = y - 1; found_glyph && yy <= y + 1; yy++) {
|
||||
int idx = yy*(xlen+1);
|
||||
for (int xx = x - 1; xx <= x + 1; xx++) {
|
||||
char map_ch = map[k][ yy - y + 1 ][ xx - x + 1 ];
|
||||
|
||||
if (IsInside(xx, yy)) {
|
||||
char c = *(screen + idx + xx);
|
||||
if (!IsGraphic( c ) && (map_ch == '|')) {
|
||||
found_glyph = false;
|
||||
break;
|
||||
} else if (IsGraphic( c ) && (map_ch == '.')) {
|
||||
found_glyph = false;
|
||||
break;
|
||||
}
|
||||
} else if (map_ch == '|') {
|
||||
found_glyph = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
idx += xlen+1;
|
||||
}
|
||||
|
||||
if (found_glyph) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_glyph) {
|
||||
*(screen + y*(xlen+1) + x) = 0x80 + k;
|
||||
}
|
||||
}
|
||||
|
||||
void video_interface_translate_screen_x_y(char *screen, const int xlen, const int ylen) {
|
||||
for (int idx=0, y=0; y < ylen; y++, idx+=xlen+1) {
|
||||
for (int x = 0; x < xlen; x++) {
|
||||
if (*(screen + idx + x) == '|') {
|
||||
_convert_screen_graphics(screen, x, y, xlen, ylen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void video_interface_print_submenu_centered_fb(uint8_t *fb, int submenu_width, int submenu_height, char *submenu, const int xlen, const int ylen) {
|
||||
video_interface_translate_screen_x_y(submenu, xlen, ylen);
|
||||
int x = (submenu_width - xlen) >> 1;
|
||||
int y = (submenu_height - ylen) >> 1;
|
||||
int fb_width = (submenu_width*7) + INTERPOLATED_PIXEL_ADJUSTMENT; // HACK NOTE : interpolated pixel adjustment still necessary ...
|
||||
int ymax = y+ylen;
|
||||
for (int idx=0; y < ymax; y++, idx+=xlen+1) {
|
||||
video_interface_print_fb(fb, fb_width, x, y, 2, &submenu[ idx ]);
|
||||
}
|
||||
}
|
||||
|
||||
void video_interface_print_submenu_centered(char *submenu, const int xlen, const int ylen) {
|
||||
video_interface_print_submenu_centered_fb(video__fb1, INTERFACE_SCREEN_X, TEXT_ROWS, submenu, xlen, ylen);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Double-Hires GRaphics
|
||||
|
||||
|
@ -1052,7 +1183,7 @@ void video_init(void) {
|
|||
#if !defined(__APPLE__)
|
||||
#if !defined(ANDROID)
|
||||
if (!is_headless) {
|
||||
video_driver_init((void *)0);
|
||||
video_backend->init((void*)0);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -1062,7 +1193,7 @@ void video_init(void) {
|
|||
void video_shutdown(void) {
|
||||
#if !HEADLESS
|
||||
if (!is_headless) {
|
||||
video_driver_shutdown();
|
||||
video_backend->shutdown();
|
||||
}
|
||||
#if !defined(__APPLE__)
|
||||
exit(0);
|
||||
|
@ -1072,7 +1203,7 @@ void video_shutdown(void) {
|
|||
|
||||
void video_main_loop(void) {
|
||||
#if !HEADLESS
|
||||
video_driver_main_loop();
|
||||
video_backend->main_loop();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
202
src/interface.c
202
src/interface.c
|
@ -16,27 +16,20 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
static struct stat statbuf = { 0 };
|
||||
static int altdrive = 0;
|
||||
|
||||
bool in_interface = false;
|
||||
|
||||
static struct stat statbuf;
|
||||
static int altdrive;
|
||||
|
||||
/*#define undoc_supported 1*/
|
||||
/*#else*/
|
||||
/*#define undoc_supported 0*/
|
||||
|
||||
void copy_and_pad_string(char *dest, const char* src, const char c, const int len, const char cap)
|
||||
{
|
||||
const char* p;
|
||||
void copy_and_pad_string(char *dest, const char* src, const char c, const int len, const char cap) {
|
||||
const char* p = src;
|
||||
char* d = dest;
|
||||
|
||||
for (p = src; ((*p != '\0') && (p-src < len-1)); p++)
|
||||
{
|
||||
for (; ((*p != '\0') && (p-src < len-1)); p++) {
|
||||
*d++ = *p;
|
||||
}
|
||||
|
||||
while (d-dest < len-1)
|
||||
{
|
||||
while (d-dest < len-1) {
|
||||
*d++ = c;
|
||||
}
|
||||
|
||||
|
@ -44,199 +37,46 @@ void copy_and_pad_string(char *dest, const char* src, const char c, const int le
|
|||
}
|
||||
|
||||
static void pad_string(char *s, const char c, const int len) {
|
||||
char *p;
|
||||
char *p = s;
|
||||
|
||||
for (p = s; ((*p != '\0') && (p-s < len-1)); p++)
|
||||
{
|
||||
for (; ((*p != '\0') && (p-s < len-1)); p++) {
|
||||
// counting ...
|
||||
}
|
||||
|
||||
while (p-s < len-1)
|
||||
{
|
||||
while (p-s < len-1) {
|
||||
*p++ = c;
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
c_load_interface_font()
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void c_load_interface_font()
|
||||
{
|
||||
video_loadfont_int(0x00,0x40,ucase_glyphs);
|
||||
video_loadfont_int(0x40,0x20,ucase_glyphs);
|
||||
video_loadfont_int(0x60,0x20,lcase_glyphs);
|
||||
video_loadfont_int(0x80,0x40,ucase_glyphs);
|
||||
video_loadfont_int(0xC0,0x20,ucase_glyphs);
|
||||
video_loadfont_int(0xE0,0x20,lcase_glyphs);
|
||||
|
||||
video_loadfont_int(0x80,11,interface_glyphs);
|
||||
video_loadfont_int(MOUSETEXT_BEGIN,0x20,mousetext_glyphs);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
c_interface_print()
|
||||
------------------------------------------------------------------------- */
|
||||
void c_interface_print( int x, int y, int cs, const char *s )
|
||||
{
|
||||
for (; *s; x++, s++)
|
||||
{
|
||||
video_plotchar( x, y, cs, *s );
|
||||
}
|
||||
void c_interface_print( int x, int y, int cs, const char *s ) {
|
||||
video_interface_print(x, y, cs, s);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
c_interface_print_screen()
|
||||
------------------------------------------------------------------------- */
|
||||
void c_interface_print_screen( char screen[24][INTERFACE_SCREEN_X+1] )
|
||||
{
|
||||
for (int y = 0; y < 24; y++)
|
||||
{
|
||||
void c_interface_print_screen( char screen[24][INTERFACE_SCREEN_X+1] ) {
|
||||
for (int y = 0; y < 24; y++) {
|
||||
c_interface_print( 0, y, 2, screen[ y ] );
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
c_interface_translate_screen()
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
#define IsGraphic(c) ((c) == '|' || (((unsigned char)c) >= 0x80 && ((unsigned char)c) <= 0x8A))
|
||||
#define IsInside(x,y) ((x) >= 0 && (x) <= xlen-1 && (y) >= 0 && (y) <= ylen-1)
|
||||
|
||||
static void _convert_screen_graphics( char *screen, const int x, const int y, const int xlen, const int ylen )
|
||||
{
|
||||
static char map[11][3][4] ={ { "...",
|
||||
".||",
|
||||
".|." },
|
||||
|
||||
{ "...",
|
||||
"||.",
|
||||
".|." },
|
||||
|
||||
{ ".|.",
|
||||
".||",
|
||||
"..." },
|
||||
|
||||
{ ".|.",
|
||||
"||.",
|
||||
"..." },
|
||||
|
||||
{ "~|~",
|
||||
".|.",
|
||||
"~|~" },
|
||||
|
||||
{ "~.~",
|
||||
"|||",
|
||||
"~.~" },
|
||||
|
||||
{ ".|.",
|
||||
".||",
|
||||
".|." },
|
||||
|
||||
{ ".|.",
|
||||
"||.",
|
||||
".|." },
|
||||
|
||||
{ "...",
|
||||
"|||",
|
||||
".|." },
|
||||
|
||||
{ ".|.",
|
||||
"|||",
|
||||
"..." },
|
||||
|
||||
{ ".|.",
|
||||
"|||",
|
||||
".|." } };
|
||||
|
||||
bool found_glyph = false;
|
||||
int k = 10;
|
||||
for (; k >= 0; k--)
|
||||
{
|
||||
found_glyph = true;
|
||||
|
||||
for (int yy = y - 1; found_glyph && yy <= y + 1; yy++)
|
||||
{
|
||||
int idx = yy*(xlen+1);
|
||||
for (int xx = x - 1; xx <= x + 1; xx++)
|
||||
{
|
||||
char map_ch = map[k][ yy - y + 1 ][ xx - x + 1 ];
|
||||
|
||||
if (IsInside(xx, yy))
|
||||
{
|
||||
char c = *(screen + idx + xx);
|
||||
if (!IsGraphic( c ) && (map_ch == '|'))
|
||||
{
|
||||
found_glyph = false;
|
||||
break;
|
||||
}
|
||||
else if (IsGraphic( c ) && (map_ch == '.'))
|
||||
{
|
||||
found_glyph = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (map_ch == '|')
|
||||
{
|
||||
found_glyph = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
idx += xlen+1;
|
||||
}
|
||||
|
||||
if (found_glyph)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_glyph)
|
||||
{
|
||||
*(screen + y*(xlen+1) + x) = 0x80 + k;
|
||||
}
|
||||
static void c_interface_translate_screen_x_y(char *screen, const int xlen, const int ylen) {
|
||||
video_interface_translate_screen_x_y(screen, xlen, ylen);
|
||||
}
|
||||
|
||||
static void c_interface_translate_screen_x_y(char *screen, const int xlen, const int ylen)
|
||||
{
|
||||
for (int idx=0, y=0; y < ylen; y++, idx+=xlen+1)
|
||||
{
|
||||
for (int x = 0; x < xlen; x++)
|
||||
{
|
||||
if (*(screen + idx + x) == '|')
|
||||
{
|
||||
_convert_screen_graphics(screen, x, y, xlen, ylen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void c_interface_translate_screen( char screen[24][INTERFACE_SCREEN_X+1] )
|
||||
{
|
||||
|
||||
void c_interface_translate_screen( char screen[24][INTERFACE_SCREEN_X+1] ) {
|
||||
c_interface_translate_screen_x_y(screen[0], INTERFACE_SCREEN_X, 24);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
c_interface_print_submenu_centered()
|
||||
------------------------------------------------------------------------- */
|
||||
void c_interface_print_submenu_centered( char *submenu, const int xlen, const int ylen )
|
||||
{
|
||||
c_interface_translate_screen_x_y(submenu, xlen, ylen);
|
||||
int x = (INTERFACE_SCREEN_X - xlen) >> 1;
|
||||
int y = (24 - ylen) >> 1;
|
||||
|
||||
int ymax = y+ylen;
|
||||
for (int idx=0; y < ymax; y++, idx+=xlen+1)
|
||||
{
|
||||
c_interface_print( x, y, 2, &submenu[ idx ] );
|
||||
}
|
||||
void c_interface_print_submenu_centered( char *submenu, const int xlen, const int ylen ) {
|
||||
video_interface_print_submenu_centered(submenu, xlen, ylen);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
static int c_interface_cut_name(char *name)
|
||||
{
|
||||
char *p = name + strlen(name) - 1;
|
||||
|
@ -1280,8 +1120,10 @@ void c_interface_parameters()
|
|||
#ifdef __linux__
|
||||
LOG("Back to Linux, w00t!\n");
|
||||
#endif
|
||||
#ifdef AUDIO_ENABLED
|
||||
speaker_destroy();
|
||||
MB_Destroy();
|
||||
#endif
|
||||
|
||||
video_shutdown();
|
||||
exit( 0 );
|
||||
|
|
|
@ -17,16 +17,13 @@
|
|||
#ifndef A2_INTERFACE_H
|
||||
#define A2_INTERFACE_H
|
||||
|
||||
#define INTERFACE_SCREEN_X 80
|
||||
|
||||
#define MOUSETEXT_BEGIN 0x90
|
||||
#include "video/video.h"
|
||||
|
||||
extern bool in_interface;
|
||||
|
||||
void c_interface_begin(int current_key);
|
||||
void c_interface_print(int x, int y, const int cs, const char *s);
|
||||
void c_interface_print_submenu_centered(char *submenu, const int xlen, const int ylen);
|
||||
void c_load_interface_font();
|
||||
void c_interface_keyboard_layout();
|
||||
void c_interface_parameters();
|
||||
void c_interface_credits();
|
||||
|
|
66
src/keys.c
66
src/keys.c
|
@ -254,6 +254,72 @@ void c_keys_handle_input(int scancode, int pressed, int is_cooked)
|
|||
timing_toggle_cpu_speed();
|
||||
break;
|
||||
}
|
||||
//#define CPUSCALE_ANIMATIONS_KEYS 1
|
||||
#if CPUSCALE_ANIMATIONS_KEYS
|
||||
if (current_key == kF3) {
|
||||
|
||||
double scale = (alt_speed_enabled ? cpu_altscale_factor : cpu_scale_factor);
|
||||
int percent_scale = (int)round(scale * 100);
|
||||
if (scale == CPU_SCALE_FASTEST) {
|
||||
scale = CPU_SCALE_FASTEST0;
|
||||
percent_scale = (int)round(scale * 100);
|
||||
} else {
|
||||
if (percent_scale > 100) {
|
||||
percent_scale -= 25;
|
||||
} else {
|
||||
percent_scale -= 5;
|
||||
}
|
||||
}
|
||||
scale = percent_scale/100.0;
|
||||
|
||||
if (scale < CPU_SCALE_SLOWEST) {
|
||||
scale = CPU_SCALE_SLOWEST;
|
||||
}
|
||||
|
||||
if (alt_speed_enabled) {
|
||||
cpu_altscale_factor = scale;
|
||||
} else {
|
||||
cpu_scale_factor = scale;
|
||||
}
|
||||
|
||||
if (video_animation_show_cpuspeed) {
|
||||
video_animation_show_cpuspeed();
|
||||
}
|
||||
#warning HACK TODO FIXME ... refactor timing stuff
|
||||
timing_toggle_cpu_speed();
|
||||
timing_toggle_cpu_speed();
|
||||
break;
|
||||
}
|
||||
if (current_key == kF4) {
|
||||
|
||||
int percent_scale = (int)round((alt_speed_enabled ? cpu_altscale_factor : cpu_scale_factor) * 100);
|
||||
double scale = 0.0;
|
||||
if (percent_scale >= 100) {
|
||||
percent_scale += 25;
|
||||
} else {
|
||||
percent_scale += 5;
|
||||
}
|
||||
scale = percent_scale/100.0;
|
||||
|
||||
if (scale > CPU_SCALE_FASTEST) {
|
||||
scale = CPU_SCALE_FASTEST;
|
||||
}
|
||||
|
||||
if (alt_speed_enabled) {
|
||||
cpu_altscale_factor = scale;
|
||||
} else {
|
||||
cpu_scale_factor = scale;
|
||||
}
|
||||
|
||||
if (video_animation_show_cpuspeed) {
|
||||
video_animation_show_cpuspeed();
|
||||
}
|
||||
#warning HACK TODO FIXME ... refactor timing stuff
|
||||
timing_toggle_cpu_speed();
|
||||
timing_toggle_cpu_speed();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (current_key == kEND)
|
||||
|
|
|
@ -593,12 +593,8 @@ void reinitialize(void) {
|
|||
}
|
||||
|
||||
void c_initialize_firsttime(void) {
|
||||
#ifdef INTERFACE_CLASSIC
|
||||
/* read in system files and calculate system defaults */
|
||||
c_load_interface_font();
|
||||
#endif
|
||||
video_load_interface_fonts();
|
||||
|
||||
/* initialize the video system */
|
||||
video_init();
|
||||
|
||||
#ifdef DEBUGGER
|
||||
|
|
|
@ -64,7 +64,7 @@ static bool auto_adjust_speed = true;
|
|||
double cpu_scale_factor = 1.0;
|
||||
double cpu_altscale_factor = 1.0;
|
||||
bool is_fullspeed = false;
|
||||
static bool alt_speed_enabled = false;
|
||||
bool alt_speed_enabled = false;
|
||||
|
||||
// misc
|
||||
volatile uint8_t emul_reinitialize = 0;
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#define CLK_6502_INT ((_M14_INT * 65) / 912)
|
||||
|
||||
#define CPU_SCALE_SLOWEST 0.25
|
||||
#define CPU_SCALE_FASTEST0 4.0
|
||||
#define CPU_SCALE_FASTEST 4.05
|
||||
#ifdef INTERFACE_CLASSIC
|
||||
# define CPU_SCALE_STEP_DIV 0.01
|
||||
|
@ -50,6 +51,7 @@ extern int cycles_speaker_feedback; // current -/+ speaker requested fee
|
|||
extern double cpu_scale_factor; // scale factor #1
|
||||
extern double cpu_altscale_factor; // scale factor #2
|
||||
extern bool is_fullspeed; // emulation in full native speed?
|
||||
extern bool alt_speed_enabled;
|
||||
|
||||
extern pthread_t cpu_thread_id;
|
||||
extern pthread_mutex_t interface_mutex;
|
||||
|
|
|
@ -12,19 +12,39 @@ precision highp float;
|
|||
// above.
|
||||
|
||||
#if __VERSION__ >= 140
|
||||
in vec2 varTexcoord;
|
||||
out vec4 fragColor;
|
||||
in vec2 varTexcoord;
|
||||
out vec4 fragColor;
|
||||
#else
|
||||
varying vec2 varTexcoord;
|
||||
#endif
|
||||
|
||||
uniform sampler2D diffuseTexture;
|
||||
// global alpha value
|
||||
uniform float aValue;
|
||||
|
||||
// texture switch
|
||||
uniform int tex2Use;
|
||||
|
||||
// Framebuffer
|
||||
uniform sampler2D framebufferTexture;
|
||||
|
||||
// Floating message
|
||||
uniform sampler2D messageTexture;
|
||||
|
||||
#if __VERSION__ >= 140
|
||||
#define OUTPUT_TEXTURE(TEX) \
|
||||
vec4 tex = texture(TEX, varTexcoord.st, 0.0); \
|
||||
fragColor = vec4(tex.r, tex.g, tex.b, 1.0*aValue)
|
||||
#else
|
||||
#define OUTPUT_TEXTURE(TEX) \
|
||||
vec4 tex = texture2D(TEX, varTexcoord.st, 0.0); \
|
||||
gl_FragColor = vec4(tex.r, tex.g, tex.b, 1.0*aValue)
|
||||
#endif
|
||||
|
||||
void main(void)
|
||||
{
|
||||
#if __VERSION__ >= 140
|
||||
fragColor = texture(diffuseTexture, varTexcoord.st, 0.0);
|
||||
#else
|
||||
gl_FragColor = texture2D(diffuseTexture, varTexcoord.st, 0.0);
|
||||
#endif
|
||||
if (tex2Use == 1) {
|
||||
OUTPUT_TEXTURE(messageTexture);
|
||||
} else {
|
||||
OUTPUT_TEXTURE(framebufferTexture);
|
||||
}
|
||||
}
|
||||
|
|
76
src/video/glanimation.c
Normal file
76
src/video/glanimation.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Apple // emulator for *nix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 2 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* THERE ARE NO WARRANTIES WHATSOEVER.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "video/glanimation.h"
|
||||
#include "video/glvideo.h"
|
||||
|
||||
void (*video_animation_show_cpuspeed)(void) = NULL;
|
||||
void (*video_animation_show_track_sector)(int drive, int track, int sect) = NULL;
|
||||
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
typedef struct glanim_array_node_t {
|
||||
struct glanim_array_node_t *next;
|
||||
glanim_t *anim;
|
||||
} glanim_array_node_t;
|
||||
|
||||
static glanim_array_node_t *animations = NULL;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void gldriver_register_animation(glanim_t *anim) {
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
glanim_array_node_t *node = malloc(sizeof(glanim_array_node_t));
|
||||
assert(node);
|
||||
node->next = NULL;
|
||||
node->anim = anim;
|
||||
|
||||
if (animations == NULL) {
|
||||
animations = node;
|
||||
} else {
|
||||
glanim_array_node_t *p = animations;
|
||||
while (p->next) {
|
||||
p = p->next;
|
||||
}
|
||||
p->next = node;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void gldriver_animation_init(void) {
|
||||
LOG("gldriver_animation_init ...");
|
||||
glanim_array_node_t *p = animations;
|
||||
while (p) {
|
||||
p->anim->ctor();
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
void gldriver_animation_destroy(void) {
|
||||
LOG("gldriver_animation_destroy ...");
|
||||
glanim_array_node_t *p = animations;
|
||||
while (p) {
|
||||
p->anim->dtor();
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
void gldriver_animation_render(void) {
|
||||
glanim_array_node_t *p = animations;
|
||||
while (p) {
|
||||
p->anim->render();
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
40
src/video/glanimation.h
Normal file
40
src/video/glanimation.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Apple // emulator for *nix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 2 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* THERE ARE NO WARRANTIES WHATSOEVER.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifndef _GLANIMATION_H_
|
||||
#define _GLANIMATION_H_
|
||||
|
||||
typedef void (*glanim_ctor_fn)(void);
|
||||
typedef void (*glanim_dtor_fn)(void);
|
||||
typedef void (*glanim_render_fn)(void);
|
||||
|
||||
typedef struct glanim_t {
|
||||
glanim_ctor_fn ctor;
|
||||
glanim_dtor_fn dtor;
|
||||
glanim_render_fn render;
|
||||
} glanim_t;
|
||||
|
||||
// register an animation
|
||||
void gldriver_register_animation(glanim_t *anim);
|
||||
|
||||
// initialize animations module
|
||||
void gldriver_animation_init(void);
|
||||
|
||||
// destroy animations module
|
||||
void gldriver_animation_destroy(void);
|
||||
|
||||
// renders the animation
|
||||
void gldriver_animation_render(void);
|
||||
|
||||
#endif
|
||||
|
408
src/video/glcpuanim.c
Normal file
408
src/video/glcpuanim.c
Normal file
|
@ -0,0 +1,408 @@
|
|||
/*
|
||||
* Apple // emulator for *nix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 2 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* THERE ARE NO WARRANTIES WHATSOEVER.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "video/glanimation.h"
|
||||
#include "video/glvideo.h"
|
||||
|
||||
#define CPUTIMING_TEMPLATE_COLS 8
|
||||
#define CPUTIMING_TEMPLATE_ROWS 3
|
||||
|
||||
// HACK NOTE FIXME TODO : interpolated pixel adjustment still necessary ...
|
||||
#define MESSAGE_FB_WIDTH ((CPUTIMING_TEMPLATE_COLS * FONT80_WIDTH_PIXELS) + INTERPOLATED_PIXEL_ADJUSTMENT)
|
||||
#define MESSAGE_FB_HEIGHT (CPUTIMING_TEMPLATE_ROWS * FONT_HEIGHT_PIXELS)
|
||||
|
||||
static bool animation_subsystem_functional = false;
|
||||
|
||||
static char cputiming_template[CPUTIMING_TEMPLATE_ROWS][CPUTIMING_TEMPLATE_COLS+1] = {
|
||||
"||||||||",
|
||||
"| xxx% |",
|
||||
"||||||||",
|
||||
};
|
||||
|
||||
static struct timespec cputiming_begin = { 0 };
|
||||
static bool cputiming_enabled = true;
|
||||
static bool texture_dirty = true;
|
||||
|
||||
static demoModel *cpuMessageObjModel = NULL;
|
||||
static GLuint cpuMessageObjVAOName = UNINITIALIZED_GL;
|
||||
static GLenum cpuMessageObjElementType = UNINITIALIZED_GL;
|
||||
static GLuint cpuMessageObjNumElements = UNINITIALIZED_GL;
|
||||
static GLuint cpuMessageObjTextureName = UNINITIALIZED_GL;
|
||||
static GLuint cpuMessageObjPosBufferName = UNINITIALIZED_GL;
|
||||
static GLuint cpuMessageObjTexcoordBufferName = UNINITIALIZED_GL;
|
||||
static GLuint cpuMessageObjElementBufferName = UNINITIALIZED_GL;
|
||||
|
||||
static uint8_t cpuMessageFB[MESSAGE_FB_WIDTH * MESSAGE_FB_HEIGHT] = { 0 };
|
||||
static uint8_t cpuMessagePixels[MESSAGE_FB_WIDTH * MESSAGE_FB_HEIGHT * 4] = { 0 };// RGBA8888
|
||||
static glanim_t cpuMessageAnimation = { 0 };
|
||||
|
||||
static void _create_message_model(void) {
|
||||
|
||||
const GLfloat messageObj_positions[] = {
|
||||
-0.3, -0.3, -0.1, 1.0,
|
||||
0.3, -0.3, -0.1, 1.0,
|
||||
-0.3, 0.3, -0.1, 1.0,
|
||||
0.3, 0.3, -0.1, 1.0,
|
||||
};
|
||||
const GLfloat messageObj_texcoords[] = {
|
||||
0.0, 1.0,
|
||||
1.0, 1.0,
|
||||
0.0, 0.0,
|
||||
1.0, 0.0,
|
||||
};
|
||||
const GLushort indices[] = {
|
||||
0, 1, 2, 2, 1, 3
|
||||
};
|
||||
|
||||
demoModel *messageObj = calloc(1, sizeof(demoModel));
|
||||
messageObj->numVertices = 4;
|
||||
messageObj->numElements = 6;
|
||||
|
||||
messageObj->positions = malloc(sizeof(messageObj_positions));
|
||||
memcpy(messageObj->positions, &messageObj_positions[0], sizeof(messageObj_positions));
|
||||
messageObj->positionType = GL_FLOAT;
|
||||
messageObj->positionSize = 4; // x,y,z coordinates
|
||||
messageObj->positionArraySize = sizeof(messageObj_positions);
|
||||
|
||||
messageObj->texcoords = malloc(sizeof(messageObj_texcoords));
|
||||
memcpy(messageObj->texcoords, &messageObj_texcoords[0], sizeof(messageObj_texcoords));
|
||||
messageObj->texcoordType = GL_FLOAT;
|
||||
messageObj->texcoordSize = 2; // s,t coordinates
|
||||
messageObj->texcoordArraySize = sizeof(messageObj_texcoords);
|
||||
|
||||
messageObj->normals = NULL;
|
||||
messageObj->normalType = GL_NONE;
|
||||
messageObj->normalSize = GL_NONE;
|
||||
messageObj->normalArraySize = 0;
|
||||
|
||||
messageObj->elements = malloc(sizeof(indices));
|
||||
memcpy(messageObj->elements, &indices[0], sizeof(indices));
|
||||
messageObj->elementType = GL_UNSIGNED_SHORT;
|
||||
messageObj->elementArraySize = sizeof(indices);
|
||||
|
||||
mdlDestroyModel(cpuMessageObjModel);
|
||||
cpuMessageObjModel = messageObj;
|
||||
}
|
||||
|
||||
static void _create_message_VAO_VBOs(const demoModel *messageModel, GLuint *messageVAOName, GLuint *posBufferName, GLuint *texcoordBufferName, GLuint *elementBufferName) {
|
||||
|
||||
// Create a vertex array object (VAO) to cache model parameters
|
||||
#if USE_VAO
|
||||
glGenVertexArrays(1, messageVAOName);
|
||||
glBindVertexArray(*messageVAOName);
|
||||
#endif
|
||||
|
||||
// Create a vertex buffer object (VBO) to store positions and load data
|
||||
glGenBuffers(1, posBufferName);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, *posBufferName);
|
||||
glBufferData(GL_ARRAY_BUFFER, messageModel->positionArraySize, messageModel->positions, GL_STATIC_DRAW);
|
||||
|
||||
#if USE_VAO
|
||||
// Enable the position attribute for this VAO
|
||||
glEnableVertexAttribArray(POS_ATTRIB_IDX);
|
||||
|
||||
// Get the size of the position type so we can set the stride properly
|
||||
GLsizei posTypeSize = _get_gl_type_size(messageModel->positionType);
|
||||
|
||||
// Set up parmeters for position attribute in the VAO including,
|
||||
// size, type, stride, and offset in the currenly bound VAO
|
||||
// This also attaches the position VBO to the VAO
|
||||
glVertexAttribPointer(POS_ATTRIB_IDX, // What attibute index will this array feed in the vertex shader (see buildProgram)
|
||||
messageModel->positionSize, // How many elements are there per position?
|
||||
messageModel->positionType, // What is the type of this data?
|
||||
GL_FALSE, // Do we want to normalize this data (0-1 range for fixed-pont types)
|
||||
messageModel->positionSize*posTypeSize, // What is the stride (i.e. bytes between positions)?
|
||||
0); // What is the offset in the VBO to the position data?
|
||||
#endif
|
||||
|
||||
if (messageModel->texcoords) {
|
||||
// Create a VBO to store texcoords
|
||||
glGenBuffers(1, texcoordBufferName);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, *texcoordBufferName);
|
||||
|
||||
// Allocate and load texcoord data into the VBO
|
||||
glBufferData(GL_ARRAY_BUFFER, messageModel->texcoordArraySize, messageModel->texcoords, GL_STATIC_DRAW);
|
||||
|
||||
#if USE_VAO
|
||||
// Enable the texcoord attribute for this VAO
|
||||
glEnableVertexAttribArray(TEXCOORD_ATTRIB_IDX);
|
||||
|
||||
// Get the size of the texcoord type so we can set the stride properly
|
||||
GLsizei texcoordTypeSize = _get_gl_type_size(messageModel->texcoordType);
|
||||
|
||||
// Set up parmeters for texcoord attribute in the VAO including,
|
||||
// size, type, stride, and offset in the currenly bound VAO
|
||||
// This also attaches the texcoord VBO to VAO
|
||||
glVertexAttribPointer(TEXCOORD_ATTRIB_IDX, // What attibute index will this array feed in the vertex shader (see buildProgram)
|
||||
messageModel->texcoordSize, // How many elements are there per texture coord?
|
||||
messageModel->texcoordType, // What is the type of this data in the array?
|
||||
GL_TRUE, // Do we want to normalize this data (0-1 range for fixed-point types)
|
||||
messageModel->texcoordSize*texcoordTypeSize, // What is the stride (i.e. bytes between texcoords)?
|
||||
0); // What is the offset in the VBO to the texcoord data?
|
||||
#endif
|
||||
}
|
||||
|
||||
// Create a VBO to vertex array elements
|
||||
// This also attaches the element array buffer to the VAO
|
||||
glGenBuffers(1, elementBufferName);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *elementBufferName);
|
||||
|
||||
// Allocate and load vertex array element data into VBO
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, messageModel->elementArraySize, messageModel->elements, GL_STATIC_DRAW);
|
||||
|
||||
GL_ERRLOG("finished creating VAO/VBOs");
|
||||
}
|
||||
|
||||
static void _destroy_VAO_VBOs(GLuint vaoName, GLuint posBufferName, GLuint texcoordBufferName, GLuint elementBufferName) {
|
||||
|
||||
// Bind the VAO so we can get data from it
|
||||
#if USE_VAO
|
||||
glBindVertexArray(vaoName);
|
||||
|
||||
// For every possible attribute set in the VAO
|
||||
for (GLuint index = 0; index < 16; index++) {
|
||||
// Get the VBO set for that attibute
|
||||
GLuint bufName = 0;
|
||||
glGetVertexAttribiv(index , GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint*)&bufName);
|
||||
|
||||
// If there was a VBO set...
|
||||
if (bufName) {
|
||||
//...delete the VBO
|
||||
glDeleteBuffers(1, &bufName);
|
||||
}
|
||||
}
|
||||
|
||||
// Get any element array VBO set in the VAO
|
||||
{
|
||||
GLuint bufName = 0;
|
||||
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, (GLint*)&bufName);
|
||||
|
||||
// If there was a element array VBO set in the VAO
|
||||
if (bufName) {
|
||||
//...delete the VBO
|
||||
glDeleteBuffers(1, &bufName);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, delete the VAO
|
||||
glDeleteVertexArrays(1, &vaoName);
|
||||
#else
|
||||
glDeleteBuffers(1, &posBufferName);
|
||||
glDeleteBuffers(1, &texcoordBufferName);
|
||||
glDeleteBuffers(1, &elementBufferName);
|
||||
#endif
|
||||
|
||||
GL_ERRLOG("destroying VAO/VBOs");
|
||||
}
|
||||
|
||||
static void _create_message_texture(void) {
|
||||
cpuMessageObjTextureName = UNINITIALIZED_GL;
|
||||
|
||||
// Create a texture object to apply to model
|
||||
glGenTextures(1, &cpuMessageObjTextureName);
|
||||
glBindTexture(GL_TEXTURE_2D, cpuMessageObjTextureName);
|
||||
|
||||
// Set up filter and wrap modes for this texture object
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
// Indicate that pixel rows are tightly packed
|
||||
// (defaults to stride of 4 which is kind of only good for
|
||||
// RGBA or FLOAT data types)
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
// register texture with OpenGL
|
||||
glTexImage2D(GL_TEXTURE_2D, /*level*/0, /*internal format*/GL_RGBA, MESSAGE_FB_WIDTH, MESSAGE_FB_HEIGHT, /*border*/0, /*format*/GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *)cpuMessagePixels);
|
||||
|
||||
GL_ERRLOG("finished creating message texture");
|
||||
}
|
||||
|
||||
static void cpuanim_init(void) {
|
||||
LOG("gldriver_animation_init ...");
|
||||
_create_message_model();
|
||||
|
||||
cpuMessageObjVAOName = UNINITIALIZED_GL;
|
||||
cpuMessageObjPosBufferName = UNINITIALIZED_GL;
|
||||
cpuMessageObjTexcoordBufferName = UNINITIALIZED_GL;
|
||||
cpuMessageObjElementBufferName = UNINITIALIZED_GL;
|
||||
_create_message_VAO_VBOs(cpuMessageObjModel, &cpuMessageObjVAOName, &cpuMessageObjPosBufferName, &cpuMessageObjTexcoordBufferName, &cpuMessageObjElementBufferName);
|
||||
if (cpuMessageObjPosBufferName == UNINITIALIZED_GL || cpuMessageObjTexcoordBufferName == UNINITIALIZED_GL || cpuMessageObjElementBufferName == UNINITIALIZED_GL)
|
||||
{
|
||||
LOG("not initializing CPU speed animations");
|
||||
return;
|
||||
}
|
||||
|
||||
cpuMessageObjNumElements = cpuMessageObjModel->numElements;
|
||||
cpuMessageObjElementType = cpuMessageObjModel->elementType;
|
||||
|
||||
_create_message_texture();
|
||||
|
||||
animation_subsystem_functional = true;
|
||||
}
|
||||
|
||||
static void cpuanim_destroy(void) {
|
||||
LOG("gldriver_animation_destroy ...");
|
||||
if (!animation_subsystem_functional) {
|
||||
return;
|
||||
}
|
||||
|
||||
animation_subsystem_functional = false;
|
||||
|
||||
// cleanup cputiming message objects
|
||||
glDeleteTextures(1, &cpuMessageObjTextureName);
|
||||
cpuMessageObjTextureName = UNINITIALIZED_GL;
|
||||
|
||||
_destroy_VAO_VBOs(cpuMessageObjVAOName, cpuMessageObjPosBufferName, cpuMessageObjTexcoordBufferName, cpuMessageObjElementBufferName);
|
||||
cpuMessageObjVAOName = UNINITIALIZED_GL;
|
||||
cpuMessageObjPosBufferName = UNINITIALIZED_GL;
|
||||
cpuMessageObjTexcoordBufferName = UNINITIALIZED_GL;
|
||||
cpuMessageObjElementBufferName = UNINITIALIZED_GL;
|
||||
|
||||
mdlDestroyModel(cpuMessageObjModel);
|
||||
cpuMessageObjModel = NULL;
|
||||
}
|
||||
|
||||
static void _render_message_object(GLfloat alpha, GLuint vaoName, GLuint posBufferName, GLuint texcoordBufferName, GLuint elementBufferName) {
|
||||
|
||||
// Bind our vertex array object
|
||||
#if USE_VAO
|
||||
glBindVertexArray(vaoName);
|
||||
#else
|
||||
glBindBuffer(GL_ARRAY_BUFFER, posBufferName);
|
||||
|
||||
GLsizei posTypeSize = _get_gl_type_size(cpuMessageObjModel->positionType);
|
||||
GLsizei texcoordTypeSize = _get_gl_type_size(cpuMessageObjModel->texcoordType);
|
||||
|
||||
// Set up parmeters for position attribute in the VAO including, size, type, stride, and offset in the currenly
|
||||
// bound VAO This also attaches the position VBO to the VAO
|
||||
glVertexAttribPointer(POS_ATTRIB_IDX, // What attibute index will this array feed in the vertex shader (see buildProgram)
|
||||
cpuMessageObjModel->positionSize, // How many elements are there per position?
|
||||
cpuMessageObjModel->positionType, // What is the type of this data?
|
||||
GL_FALSE, // Do we want to normalize this data (0-1 range for fixed-pont types)
|
||||
cpuMessageObjModel->positionSize*posTypeSize, // What is the stride (i.e. bytes between positions)?
|
||||
0); // What is the offset in the VBO to the position data?
|
||||
glEnableVertexAttribArray(POS_ATTRIB_IDX);
|
||||
|
||||
// Set up parmeters for texcoord attribute in the VAO including, size, type, stride, and offset in the currenly
|
||||
// bound VAO This also attaches the texcoord VBO to VAO
|
||||
glBindBuffer(GL_ARRAY_BUFFER, texcoordBufferName);
|
||||
glVertexAttribPointer(TEXCOORD_ATTRIB_IDX, // What attibute index will this array feed in the vertex shader (see buildProgram)
|
||||
cpuMessageObjModel->texcoordSize, // How many elements are there per texture coord?
|
||||
cpuMessageObjModel->texcoordType, // What is the type of this data in the array?
|
||||
GL_TRUE, // Do we want to normalize this data (0-1 range for fixed-point types)
|
||||
cpuMessageObjModel->texcoordSize*texcoordTypeSize,// What is the stride (i.e. bytes between texcoords)?
|
||||
0); // What is the offset in the VBO to the texcoord data?
|
||||
glEnableVertexAttribArray(TEXCOORD_ATTRIB_IDX);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferName);
|
||||
#endif
|
||||
|
||||
glUniform1f(alphaValue, alpha);
|
||||
|
||||
// Draw the message object
|
||||
glDrawElements(GL_TRIANGLES, cpuMessageObjNumElements, cpuMessageObjElementType, 0);
|
||||
GL_ERRLOG("CPU message render");
|
||||
}
|
||||
|
||||
static void cpuanim_render(void) {
|
||||
if (!animation_subsystem_functional) {
|
||||
return;
|
||||
}
|
||||
if (!cputiming_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
float alpha = 0.95;
|
||||
struct timespec deltat = timespec_diff(cputiming_begin, now, NULL);
|
||||
if (deltat.tv_sec >= 1) {
|
||||
cputiming_enabled = false;
|
||||
return;
|
||||
} else if (deltat.tv_nsec >= NANOSECONDS_PER_SECOND/2) {
|
||||
alpha -= ((float)deltat.tv_nsec-(NANOSECONDS_PER_SECOND/2)) / (float)(NANOSECONDS_PER_SECOND/2);
|
||||
if (alpha < 0.0) {
|
||||
alpha = 0.0;
|
||||
}
|
||||
}
|
||||
//LOG("alpha : %f", alpha);
|
||||
|
||||
glActiveTexture(TEXTURE_ACTIVE_MESSAGE);
|
||||
glBindTexture(GL_TEXTURE_2D, cpuMessageObjTextureName);
|
||||
if (texture_dirty) {
|
||||
texture_dirty = false;
|
||||
glTexImage2D(GL_TEXTURE_2D, /*level*/0, /*internal format*/GL_RGBA, MESSAGE_FB_WIDTH, MESSAGE_FB_HEIGHT, /*border*/0, /*format*/GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *)cpuMessagePixels);
|
||||
}
|
||||
glUniform1i(uniformTex2Use, TEXTURE_ID_MESSAGE);
|
||||
_render_message_object(alpha, cpuMessageObjVAOName, cpuMessageObjPosBufferName, cpuMessageObjTexcoordBufferName, cpuMessageObjElementBufferName);
|
||||
}
|
||||
|
||||
static void cpuanim_show(void) {
|
||||
if (!animation_subsystem_functional) {
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[8];
|
||||
double scale = (alt_speed_enabled ? cpu_altscale_factor : cpu_scale_factor);
|
||||
int percentScale = scale * 100;
|
||||
if (percentScale < 100.0) {
|
||||
snprintf(buf, 3, "%d", percentScale);
|
||||
cputiming_template[1][2] = ' ';
|
||||
cputiming_template[1][3] = buf[0];
|
||||
cputiming_template[1][4] = buf[1];
|
||||
} else if (scale == CPU_SCALE_FASTEST) {
|
||||
cputiming_template[1][2] = 'm';
|
||||
cputiming_template[1][3] = 'a';
|
||||
cputiming_template[1][4] = 'x';
|
||||
} else {
|
||||
snprintf(buf, 4, "%d", percentScale);
|
||||
cputiming_template[1][2] = buf[0];
|
||||
cputiming_template[1][3] = buf[1];
|
||||
cputiming_template[1][4] = buf[2];
|
||||
}
|
||||
|
||||
// render template into indexed fb
|
||||
unsigned int submenu_width = CPUTIMING_TEMPLATE_COLS;
|
||||
unsigned int submenu_height = CPUTIMING_TEMPLATE_ROWS;
|
||||
char *submenu = cputiming_template[0];
|
||||
video_interface_print_submenu_centered_fb(cpuMessageFB, submenu_width, submenu_height, submenu, submenu_width, submenu_height);
|
||||
|
||||
// generate RGBA_8888 from indexed color
|
||||
unsigned int count = MESSAGE_FB_WIDTH * MESSAGE_FB_HEIGHT;
|
||||
for (unsigned int i=0, j=0; i<count; i++, j+=4) {
|
||||
uint8_t index = *(cpuMessageFB + i);
|
||||
*( (uint32_t*)(cpuMessagePixels + j) ) = (uint32_t)(
|
||||
((uint32_t)(colormap[index].red) << 0 ) |
|
||||
((uint32_t)(colormap[index].green) << 8 ) |
|
||||
((uint32_t)(colormap[index].blue) << 16) |
|
||||
((uint32_t)0xff << 24)
|
||||
);
|
||||
}
|
||||
|
||||
cputiming_enabled = true;
|
||||
texture_dirty = true;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cputiming_begin);
|
||||
}
|
||||
|
||||
__attribute__((constructor))
|
||||
static void _init_glcpuanim(void) {
|
||||
LOG("Registering CPU speed animations");
|
||||
video_animation_show_cpuspeed = &cpuanim_show;
|
||||
cpuMessageAnimation.ctor = &cpuanim_init;
|
||||
cpuMessageAnimation.dtor = &cpuanim_destroy;
|
||||
cpuMessageAnimation.render = &cpuanim_render;
|
||||
gldriver_register_animation(&cpuMessageAnimation);
|
||||
}
|
||||
|
|
@ -12,17 +12,7 @@
|
|||
// GL touch joystick -- Created by Aaron Culliney
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "video_util/modelUtil.h"
|
||||
#include "video_util/matrixUtil.h"
|
||||
#include "video_util/sourceUtil.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
// VAO optimization (may not be available on all platforms)
|
||||
#define USE_VAO 0
|
||||
#include "video/glvideo.h"
|
||||
|
||||
void gldriver_joystick_reset(void) {
|
||||
}
|
||||
|
|
|
@ -12,34 +12,9 @@
|
|||
// glvideo -- Created by Aaron Culliney
|
||||
|
||||
#include "common.h"
|
||||
#include "video/glvideo.h"
|
||||
#include "video/glinput.h"
|
||||
#include "video/renderer.h"
|
||||
|
||||
#include "video_util/modelUtil.h"
|
||||
#include "video_util/matrixUtil.h"
|
||||
#include "video_util/sourceUtil.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#define USE_VAO 1
|
||||
#endif
|
||||
|
||||
// TODO: implement 3D CRT object, possibly with perspective drawing?
|
||||
#define PERSPECTIVE 0
|
||||
|
||||
// VAO optimization (may not be available on all platforms)
|
||||
#ifdef ANDROID
|
||||
#warning YAY Awesome! Various older Android and Android-ish devices (*cough* Kindle *cough*) have buggy OpenGL VAO support, so do like Nancy and just say no
|
||||
#define USE_VAO 0
|
||||
#elif !defined(USE_VAO)
|
||||
#define USE_VAO 1
|
||||
#endif
|
||||
|
||||
enum {
|
||||
POS_ATTRIB_IDX,
|
||||
TEXCOORD_ATTRIB_IDX,
|
||||
NORMAL_ATTRIB_IDX,
|
||||
};
|
||||
#include "video/glanimation.h"
|
||||
|
||||
bool safe_to_do_opengl_logging = false;
|
||||
|
||||
|
@ -56,57 +31,42 @@ static int viewportHeight = SCANHEIGHT*1.5;
|
|||
static int adjustedHeight = 0;
|
||||
#endif
|
||||
|
||||
static GLint uniformMVPIdx;
|
||||
static GLenum crtElementType;
|
||||
static GLuint crtNumElements;
|
||||
GLint uniformTex2Use = UNINITIALIZED_GL;
|
||||
GLint alphaValue = UNINITIALIZED_GL;
|
||||
static GLint uniformMVPIdx = UNINITIALIZED_GL;
|
||||
static GLenum crtElementType = UNINITIALIZED_GL;
|
||||
static GLuint crtNumElements = UNINITIALIZED_GL;
|
||||
|
||||
static GLuint a2TextureName = 0;
|
||||
static GLuint defaultFBO = 0;
|
||||
static GLuint program = 0;
|
||||
static GLuint a2TextureName = UNINITIALIZED_GL;
|
||||
static GLuint defaultFBO = UNINITIALIZED_GL;
|
||||
static GLuint program = UNINITIALIZED_GL;
|
||||
|
||||
static GLuint crtVAOName = 0;
|
||||
static GLuint posBufferName = 0;
|
||||
static GLuint texcoordBufferName;
|
||||
static GLuint elementBufferName = 0;
|
||||
static GLuint crtVAOName = UNINITIALIZED_GL;
|
||||
static GLuint posBufferName = UNINITIALIZED_GL;
|
||||
static GLuint texcoordBufferName = UNINITIALIZED_GL;
|
||||
static GLuint elementBufferName = UNINITIALIZED_GL;
|
||||
static demoModel *crtModel = NULL;
|
||||
|
||||
static video_backend_s glvideo_backend = { 0 };
|
||||
|
||||
#if USE_GLUT
|
||||
static int glutWindow = -1;
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// OpenGL helper routines
|
||||
//
|
||||
|
||||
static inline GLsizei _get_gl_type_size(GLenum type) {
|
||||
switch (type) {
|
||||
case GL_BYTE:
|
||||
return sizeof(GLbyte);
|
||||
case GL_UNSIGNED_BYTE:
|
||||
return sizeof(GLubyte);
|
||||
case GL_SHORT:
|
||||
return sizeof(GLshort);
|
||||
case GL_UNSIGNED_SHORT:
|
||||
return sizeof(GLushort);
|
||||
case GL_INT:
|
||||
return sizeof(GLint);
|
||||
case GL_UNSIGNED_INT:
|
||||
return sizeof(GLuint);
|
||||
case GL_FLOAT:
|
||||
return sizeof(GLfloat);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _create_CRT_model(void) {
|
||||
#define STRIDE 9*sizeof(GLfloat)
|
||||
#define TEST_COLOR_OFF (GLvoid *)(3*sizeof(GLfloat))
|
||||
#define TEX_COORD_OFF (GLvoid *)(7*sizeof(GLfloat))
|
||||
|
||||
// NOTE: vertices in Normalized Device Coordinates
|
||||
const GLfloat crt_positions[] = {
|
||||
// CRT screen quad
|
||||
-1.0, -1.0, 0.0, 1.0,
|
||||
1.0, -1.0, 0.0, 1.0,
|
||||
1.0, -1.0, 0.0, 1.0,
|
||||
-1.0, 1.0, 0.0, 1.0,
|
||||
1.0, 1.0, 0.0, 1.0,
|
||||
1.0, 1.0, 0.0, 1.0,
|
||||
#if PERSPECTIVE
|
||||
// CRT back side point
|
||||
0.0, 0.0, -1.0, 1.0,
|
||||
|
@ -289,8 +249,11 @@ static void _destroy_VAO(GLuint vaoName) {
|
|||
glDeleteVertexArrays(1, &vaoName);
|
||||
#else
|
||||
glDeleteBuffers(1, &posBufferName);
|
||||
posBufferName = UNINITIALIZED_GL;
|
||||
glDeleteBuffers(1, &texcoordBufferName);
|
||||
texcoordBufferName = UNINITIALIZED_GL;
|
||||
glDeleteBuffers(1, &elementBufferName);
|
||||
elementBufferName = UNINITIALIZED_GL;
|
||||
#endif
|
||||
|
||||
GL_ERRLOG("destroying VAO/VBOs");
|
||||
|
@ -301,6 +264,7 @@ static GLuint _create_CRT_texture(void) {
|
|||
|
||||
// Create a texture object to apply to model
|
||||
glGenTextures(1, &texName);
|
||||
glActiveTexture(TEXTURE_ACTIVE_FRAMEBUFFER);
|
||||
glBindTexture(GL_TEXTURE_2D, texName);
|
||||
|
||||
// Set up filter and wrap modes for this texture object
|
||||
|
@ -498,11 +462,34 @@ static GLuint _build_program(demoSource *vertexSource, demoSource *fragmentSourc
|
|||
// Setup common program input points //
|
||||
///////////////////////////////////////
|
||||
|
||||
GLint samplerLoc = glGetUniformLocation(prgName, "diffuseTexture");
|
||||
GLint fbSamplerLoc = glGetUniformLocation(prgName, "framebufferTexture");
|
||||
if (fbSamplerLoc < 0) {
|
||||
LOG("OOPS, no framebufferTexture shader : %d", fbSamplerLoc);
|
||||
} else {
|
||||
glUniform1i(fbSamplerLoc, TEXTURE_ID_FRAMEBUFFER);
|
||||
}
|
||||
|
||||
// Indicate that the diffuse texture will be bound to texture unit 0
|
||||
GLint unit = 0;
|
||||
glUniform1i(samplerLoc, unit);
|
||||
GLint messageSamplerLoc = glGetUniformLocation(prgName, "messageTexture");
|
||||
if (messageSamplerLoc < 0) {
|
||||
LOG("OOPS, no messageSamplerLoc shader : %d", messageSamplerLoc);
|
||||
} else {
|
||||
glUniform1i(messageSamplerLoc, TEXTURE_ID_MESSAGE);
|
||||
}
|
||||
|
||||
uniformMVPIdx = glGetUniformLocation(prgName, "modelViewProjectionMatrix");
|
||||
if (uniformMVPIdx < 0) {
|
||||
LOG("OOPS, no modelViewProjectionMatrix in shader : %d", uniformMVPIdx);
|
||||
}
|
||||
|
||||
uniformTex2Use = glGetUniformLocation(prgName, "tex2Use");
|
||||
if (uniformTex2Use < 0) {
|
||||
LOG("OOPS, no texture selector in shader : %d", uniformTex2Use);
|
||||
}
|
||||
|
||||
alphaValue = glGetUniformLocation(prgName, "aValue");
|
||||
if (alphaValue < 0) {
|
||||
LOG("OOPS, no texture selector in shader : %d", alphaValue);
|
||||
}
|
||||
|
||||
GL_ERRLOG("build program");
|
||||
|
||||
|
@ -533,6 +520,8 @@ static demoSource *_create_shader_source(const char *fileName) {
|
|||
return src;
|
||||
}
|
||||
|
||||
static void gldriver_render(void);
|
||||
|
||||
static void gldriver_init_common(void) {
|
||||
LOG("%s %s", glGetString(GL_RENDERER), glGetString(GL_VERSION));
|
||||
|
||||
|
@ -578,11 +567,6 @@ static void gldriver_init_common(void) {
|
|||
srcDestroySource(vtxSource);
|
||||
srcDestroySource(frgSource);
|
||||
|
||||
uniformMVPIdx = glGetUniformLocation(program, "modelViewProjectionMatrix");
|
||||
if (uniformMVPIdx < 0) {
|
||||
LOG("No modelViewProjectionMatrix in character shader");
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
// setup static OpenGL state
|
||||
|
||||
|
@ -593,13 +577,16 @@ static void gldriver_init_common(void) {
|
|||
glEnable(GL_CULL_FACE);
|
||||
|
||||
// Always use this clear color
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// Draw our scene once without presenting the rendered image.
|
||||
// This is done in order to pre-warm OpenGL
|
||||
// We don't need to present the buffer since we don't actually want the
|
||||
// user to see this, we're only drawing as a pre-warm stage
|
||||
video_driver_render();
|
||||
gldriver_render();
|
||||
|
||||
// Check for errors to make sure all of our setup went ok
|
||||
GL_ERRLOG("finished initialization");
|
||||
|
@ -614,15 +601,19 @@ static void gldriver_init_common(void) {
|
|||
}
|
||||
|
||||
static void gldriver_shutdown(void) {
|
||||
#if USE_GLUT
|
||||
glutDestroyWindow(glutWindow);
|
||||
#endif
|
||||
// Cleanup all OpenGL objects
|
||||
glDeleteTextures(1, &a2TextureName);
|
||||
a2TextureName = 0;
|
||||
a2TextureName = UNINITIALIZED_GL;
|
||||
_destroy_VAO(crtVAOName);
|
||||
crtVAOName = 0;
|
||||
crtVAOName = UNINITIALIZED_GL;
|
||||
mdlDestroyModel(crtModel);
|
||||
crtModel = NULL;
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
program = UNINITIALIZED_GL;
|
||||
gldriver_animation_destroy();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -705,7 +696,9 @@ static void gldriver_render(void) {
|
|||
}
|
||||
}
|
||||
|
||||
glActiveTexture(TEXTURE_ACTIVE_FRAMEBUFFER);
|
||||
glBindTexture(GL_TEXTURE_2D, a2TextureName);
|
||||
glUniform1i(uniformTex2Use, TEXTURE_ID_FRAMEBUFFER);
|
||||
if (_vid_dirty) {
|
||||
glTexImage2D(GL_TEXTURE_2D, /*level*/0, /*internal format*/GL_RGBA, SCANWIDTH, SCANHEIGHT, /*border*/0, /*format*/GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *)&pixels[0]);
|
||||
}
|
||||
|
@ -728,10 +721,10 @@ static void gldriver_render(void) {
|
|||
crtModel->positionSize*posTypeSize, // What is the stride (i.e. bytes between positions)?
|
||||
0); // What is the offset in the VBO to the position data?
|
||||
glEnableVertexAttribArray(POS_ATTRIB_IDX);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, texcoordBufferName);
|
||||
|
||||
// Set up parmeters for texcoord attribute in the VAO including, size, type, stride, and offset in the currenly
|
||||
// bound VAO This also attaches the texcoord VBO to VAO
|
||||
glBindBuffer(GL_ARRAY_BUFFER, texcoordBufferName);
|
||||
glVertexAttribPointer(TEXCOORD_ATTRIB_IDX, // What attibute index will this array feed in the vertex shader (see buildProgram)
|
||||
crtModel->texcoordSize, // How many elements are there per texture coord?
|
||||
crtModel->texcoordType, // What is the type of this data in the array?
|
||||
|
@ -739,21 +732,29 @@ static void gldriver_render(void) {
|
|||
crtModel->texcoordSize*texcoordTypeSize, // What is the stride (i.e. bytes between texcoords)?
|
||||
0); // What is the offset in the VBO to the texcoord data?
|
||||
glEnableVertexAttribArray(TEXCOORD_ATTRIB_IDX);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferName);
|
||||
#endif
|
||||
|
||||
glUniform1f(alphaValue, 1.0);
|
||||
|
||||
// Cull back faces now that we no longer render
|
||||
// with an inverted matrix
|
||||
glCullFace(GL_BACK);
|
||||
//glCullFace(GL_BACK);
|
||||
|
||||
// Draw the CRT object
|
||||
// Draw the CRT object and others
|
||||
glDrawElements(GL_TRIANGLES, crtNumElements, crtElementType, 0);
|
||||
|
||||
// Prep any other objects/animations
|
||||
gldriver_animation_render();
|
||||
|
||||
_vid_dirty = false;
|
||||
|
||||
#if USE_GLUT
|
||||
glutSwapBuffers();
|
||||
#endif
|
||||
|
||||
GL_ERRLOG("gldriver_render");
|
||||
}
|
||||
|
||||
static void gldriver_reshape(int w, int h) {
|
||||
|
@ -801,7 +802,6 @@ static void gldriver_reshape(int w, int h) {
|
|||
}
|
||||
|
||||
#if USE_GLUT
|
||||
static int glutWindow = -1;
|
||||
static void gldriver_init_glut(GLuint fbo) {
|
||||
glutInit(&argc, argv);
|
||||
glutInitDisplayMode(/*GLUT_DOUBLE|*/GLUT_RGBA|GLUT_DEPTH);
|
||||
|
@ -833,9 +833,9 @@ static void gldriver_init_glut(GLuint fbo) {
|
|||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// renderer API
|
||||
// backend renderer API
|
||||
|
||||
void video_driver_init(void *fbo) {
|
||||
static void gldriver_init(void *fbo) {
|
||||
safe_to_do_opengl_logging = true;
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
|
||||
|
@ -850,26 +850,26 @@ void video_driver_init(void *fbo) {
|
|||
#else
|
||||
#error no working codepaths
|
||||
#endif
|
||||
gldriver_animation_init();
|
||||
}
|
||||
|
||||
void video_driver_main_loop(void) {
|
||||
static void gldriver_main_loop(void) {
|
||||
#if USE_GLUT
|
||||
glutMainLoop();
|
||||
#endif
|
||||
// fall through if not GLUT
|
||||
}
|
||||
|
||||
void video_driver_render(void) {
|
||||
gldriver_render();
|
||||
}
|
||||
|
||||
void video_driver_reshape(int w, int h) {
|
||||
gldriver_reshape(w, h);
|
||||
}
|
||||
|
||||
void video_driver_shutdown(void) {
|
||||
#if USE_GLUT
|
||||
glutDestroyWindow(glutWindow);
|
||||
#endif
|
||||
gldriver_shutdown();
|
||||
__attribute__((constructor))
|
||||
static void _init_glvideo(void) {
|
||||
LOG("Initializing OpenGL renderer");
|
||||
|
||||
glvideo_backend.init = &gldriver_init;
|
||||
glvideo_backend.main_loop = &gldriver_main_loop;
|
||||
glvideo_backend.reshape = &gldriver_reshape;
|
||||
glvideo_backend.render = &gldriver_render;
|
||||
glvideo_backend.shutdown = &gldriver_shutdown;
|
||||
|
||||
video_backend = &glvideo_backend;
|
||||
}
|
||||
|
||||
|
|
78
src/video/glvideo.h
Normal file
78
src/video/glvideo.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Apple // emulator for *nix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 2 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* THERE ARE NO WARRANTIES WHATSOEVER.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _GLVIDEO_H_
|
||||
#define _GLVIDEO_H_
|
||||
|
||||
#define UNINITIALIZED_GL 31337
|
||||
|
||||
#ifdef __APPLE__
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#define USE_VAO 1
|
||||
#endif
|
||||
|
||||
// TODO: implement 3D CRT object, possibly with perspective drawing?
|
||||
#define PERSPECTIVE 0
|
||||
|
||||
// VAO optimization (may not be available on all platforms)
|
||||
#ifdef ANDROID
|
||||
#include "glanimation.h"
|
||||
#warning Certain Android and Android-ish devices (*cough* Kindle *cough*) have buggy OpenGL VAO support ...
|
||||
#define USE_VAO 0
|
||||
#elif !defined(USE_VAO)
|
||||
#define USE_VAO 1
|
||||
#endif
|
||||
|
||||
#include "video_util/modelUtil.h"
|
||||
#include "video_util/matrixUtil.h"
|
||||
#include "video_util/sourceUtil.h"
|
||||
|
||||
enum {
|
||||
POS_ATTRIB_IDX,
|
||||
TEXCOORD_ATTRIB_IDX,
|
||||
NORMAL_ATTRIB_IDX,
|
||||
};
|
||||
|
||||
enum {
|
||||
TEXTURE_ID_FRAMEBUFFER=0,
|
||||
TEXTURE_ID_MESSAGE,
|
||||
};
|
||||
|
||||
enum {
|
||||
TEXTURE_ACTIVE_FRAMEBUFFER = GL_TEXTURE0,
|
||||
TEXTURE_ACTIVE_MESSAGE = GL_TEXTURE1,
|
||||
};
|
||||
|
||||
static inline GLsizei _get_gl_type_size(GLenum type) {
|
||||
switch (type) {
|
||||
case GL_BYTE:
|
||||
return sizeof(GLbyte);
|
||||
case GL_UNSIGNED_BYTE:
|
||||
return sizeof(GLubyte);
|
||||
case GL_SHORT:
|
||||
return sizeof(GLshort);
|
||||
case GL_UNSIGNED_SHORT:
|
||||
return sizeof(GLushort);
|
||||
case GL_INT:
|
||||
return sizeof(GLint);
|
||||
case GL_UNSIGNED_INT:
|
||||
return sizeof(GLuint);
|
||||
case GL_FLOAT:
|
||||
return sizeof(GLfloat);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern GLint uniformTex2Use;
|
||||
extern GLint alphaValue;
|
||||
|
||||
#endif
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* Apple // emulator for *nix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 2 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* THERE ARE NO WARRANTIES WHATSOEVER.
|
||||
*
|
||||
*/
|
||||
|
||||
// glvideo -- Created by Aaron Culliney
|
||||
|
||||
void video_driver_init(void *context);
|
||||
void video_driver_main_loop(void);
|
||||
void video_driver_reshape(int width, int height);
|
||||
void video_driver_render(void);
|
||||
void video_driver_shutdown(void);
|
|
@ -17,37 +17,53 @@
|
|||
#ifndef A2_VIDEO_H
|
||||
#define A2_VIDEO_H
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
typedef struct video_backend_s {
|
||||
void (*init)(void *context);
|
||||
void (*main_loop)(void);
|
||||
void (*reshape)(int width, int height);
|
||||
void (*render)(void);
|
||||
void (*shutdown)(void);
|
||||
} video_backend_s;
|
||||
|
||||
typedef struct A2Color {
|
||||
/*
|
||||
* Color structure
|
||||
*/
|
||||
typedef struct A2Color_s {
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
} A2Color;
|
||||
} A2Color_s;
|
||||
|
||||
/*
|
||||
* Reference to the internal 8bit-indexed color format
|
||||
*/
|
||||
extern A2Color colormap[];
|
||||
extern A2Color_s colormap[];
|
||||
|
||||
#include "prefs.h"
|
||||
/*
|
||||
* The registered video backend (renderer).
|
||||
*/
|
||||
extern video_backend_s *video_backend;
|
||||
|
||||
/* Prepare the video system, converting console to graphics mode, or
|
||||
/*
|
||||
* Prepare the video system, converting console to graphics mode, or
|
||||
* opening X window, or whatever. This is called only once when the
|
||||
* emulator is run
|
||||
*/
|
||||
void video_init(void);
|
||||
|
||||
/* Begin main video loop (does not return)
|
||||
/*
|
||||
* Begin main video loop (does not return)
|
||||
*/
|
||||
void video_main_loop(void);
|
||||
|
||||
/* Undo anything done by video_init() and video_start(). Called before exiting the
|
||||
/*
|
||||
* Undo anything done by video_init() and video_start(). Called before exiting the
|
||||
* emulator.
|
||||
*/
|
||||
void video_shutdown(void);
|
||||
|
||||
/* Setup the display. This may be called multiple times in a run, and is
|
||||
/*
|
||||
* Setup the display. This may be called multiple times in a run, and is
|
||||
* used when graphics parameters (II+ vs //e, hires color representation) may
|
||||
* have changed.
|
||||
*
|
||||
|
@ -62,7 +78,8 @@ void video_shutdown(void);
|
|||
*/
|
||||
void video_set(int flags);
|
||||
|
||||
/* Set the font used by the display. QTY characters are loaded starting
|
||||
/*
|
||||
* Set the font used by the display. QTY characters are loaded starting
|
||||
* with FIRST, from DATA. DATA contains 8 bytes for each character, each
|
||||
* byte representing a row (top-to-bottom). The row byte contains 7
|
||||
* pixels in little-endian format.
|
||||
|
@ -80,37 +97,25 @@ void video_set(int flags);
|
|||
*/
|
||||
void video_loadfont(int first, int qty, const uint8_t *data, int mode);
|
||||
|
||||
/* Redraw the display. This is called after exiting an interface display,
|
||||
/*
|
||||
* Loads the interface/messages to a seperate character table for system menus/messages
|
||||
*/
|
||||
void video_load_interface_fonts(void);
|
||||
|
||||
/*
|
||||
* Redraw the display. This is called after exiting an interface display,
|
||||
* when changes have been made to the Apple's emulated framebuffer that
|
||||
* bypass the driver's hooks, or when the video mode has changed.
|
||||
*/
|
||||
void video_redraw(void);
|
||||
|
||||
/* Change the displayed video page to PAGE
|
||||
/*
|
||||
* Change the displayed video page to PAGE
|
||||
* 0 - Page 1: $400-$7ff/$2000-$3fff
|
||||
* 1 - Page 2: $800-$bff/$4000-$5fff
|
||||
*/
|
||||
void video_setpage(int page);
|
||||
|
||||
#ifdef INTERFACE_CLASSIC
|
||||
/* Like loadfont, but writes to a seperate 256 character table used by
|
||||
* video_plotchar and not the apple text-mode display.
|
||||
*/
|
||||
void video_loadfont_int(int first, int qty, const uint8_t *data);
|
||||
|
||||
/* Plot a character to the text mode screen, *not* writing to apple
|
||||
* memory. This is used by the interface screens.
|
||||
*
|
||||
* ROW, COL, and CODE are self-expanatory. COLOR gives the color scheme
|
||||
* to use:
|
||||
*
|
||||
* 0 - Green text on Black background
|
||||
* 1 - Green text on Blue background
|
||||
* 2 - Red text on Black background
|
||||
*/
|
||||
void video_plotchar(int row, int col, int color, uint8_t code);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get a reference to current internal framebuffer
|
||||
*/
|
||||
|
@ -121,6 +126,49 @@ const uint8_t * const video_current_framebuffer();
|
|||
*/
|
||||
bool video_dirty(void);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Plot a character to the text mode screen, *not* writing to apple
|
||||
* memory. This is used by the interface screens.
|
||||
*
|
||||
* ROW, COL, and CODE are self-expanatory. COLOR gives the color scheme
|
||||
* to use:
|
||||
*
|
||||
* 0 - Green text on Black background
|
||||
* 1 - Green text on Blue background
|
||||
* 2 - Red text on Black background
|
||||
*/
|
||||
void video_plotchar(int row, int col, int color, uint8_t code);
|
||||
|
||||
/*
|
||||
* Same as video_plotchar(), but allows plotting to a separate buffer
|
||||
*/
|
||||
void video_plotchar_fb(uint8_t *fb, int fb_width, int row, int col, int color, uint8_t code);
|
||||
|
||||
void video_interface_print(int x, int y, const int cs, const char *s);
|
||||
|
||||
void video_interface_print_fb(uint8_t *fb, int fb_width, int x, int y, const int cs, const char *s);
|
||||
|
||||
void video_interface_print_submenu_centered(char *submenu, const int xlen, const int ylen);
|
||||
|
||||
void video_interface_print_submenu_centered_fb(uint8_t *fb, int screen_char_width, int screen_char_height, char *submenu, const int xlen, const int ylen);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
/*
|
||||
* Show CPU speed animation
|
||||
*/
|
||||
extern void (*video_animation_show_cpuspeed)(void);
|
||||
|
||||
/*
|
||||
* Show track/sector animation
|
||||
*/
|
||||
extern void (*video_animation_show_track_sector)(int drive, int track, int sect);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* VBL routines
|
||||
*/
|
||||
|
@ -128,18 +176,30 @@ uint16_t video_scanner_get_address(bool *vblBarOut);
|
|||
uint8_t floating_bus(void);
|
||||
uint8_t floating_bus_hibit(const bool hibit);
|
||||
|
||||
#endif /* !__ASSEMBLER__ */
|
||||
|
||||
/**** Private stuff follows *****/
|
||||
|
||||
/* 640x400 mode really isn't what it advertises. It's really 560x384 with 4
|
||||
/*
|
||||
* 640x400 mode really isn't what it advertises. It's really 560x384 with 4
|
||||
* extra bytes on each side for color interpolation hack. This is yet another
|
||||
* area where I've traded the optimization gain (especially on older slower
|
||||
* machines) for a standard resolution.
|
||||
*/
|
||||
#define SCANWIDTH 568
|
||||
#define _SCANWIDTH 560
|
||||
#define INTERPOLATED_PIXEL_ADJUSTMENT (4+4)
|
||||
#define SCANWIDTH (_SCANWIDTH+INTERPOLATED_PIXEL_ADJUSTMENT)
|
||||
#define SCANHEIGHT 384
|
||||
#define SCANSTEP SCANWIDTH-12
|
||||
|
||||
#define TEXT_ROWS 24
|
||||
#define BEGIN_MIX 20
|
||||
#define TEXT_COLS 40
|
||||
#define TEXT80_COLS 80
|
||||
|
||||
#define INTERFACE_SCREEN_X TEXT80_COLS
|
||||
|
||||
#define FONT_HEIGHT_PIXELS 16
|
||||
#define FONT_WIDTH_PIXELS 14
|
||||
#define FONT80_WIDTH_PIXELS 7
|
||||
|
||||
#define MOUSETEXT_BEGIN 0x90
|
||||
|
||||
#define COLOR_BLACK 0
|
||||
|
||||
|
@ -177,14 +237,13 @@ uint8_t floating_bus_hibit(const bool hibit);
|
|||
#define COLOR_FLASHING_GREEN 59
|
||||
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
/* ----------------------------------
|
||||
generic graphics globals
|
||||
---------------------------------- */
|
||||
|
||||
/* Pointers to framebuffer (can be VGA memory or host buffer)
|
||||
/*
|
||||
* Pointers to framebuffer (can be VGA memory or host buffer)
|
||||
*/
|
||||
|
||||
extern uint8_t *video__fb1,*video__fb2;
|
||||
|
||||
extern uint8_t video__hires_even[0x800];
|
||||
|
@ -219,6 +278,5 @@ video__write_2e_even1(),
|
|||
video__write_2e_odd1_mixed(),
|
||||
video__write_2e_even1_mixed();
|
||||
|
||||
#endif /* !__ASSEMBLER__ */
|
||||
|
||||
#endif /* !A2_VIDEO_H */
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user