mirror of
https://github.com/mauiaaron/apple2.git
synced 2024-06-29 04:29:31 +00:00
213 lines
8.1 KiB
C
213 lines
8.1 KiB
C
/*
|
|
* Apple // emulator for *ix
|
|
*
|
|
* This software package is subject to the GNU General Public License
|
|
* version 3 or later (your choice) as published by the Free Software
|
|
* Foundation.
|
|
*
|
|
* Copyright 2013-2015 Aaron Culliney
|
|
*
|
|
*/
|
|
|
|
#include "glhudmodel.h"
|
|
#include "glvideo.h"
|
|
|
|
void *glhud_createDefault(void) {
|
|
return glhud_createCustom(sizeof(GLModelHUDElement));
|
|
}
|
|
|
|
void *glhud_createCustom(unsigned int sizeofModel) {
|
|
assert(sizeof(GLModelHUDElement) <= sizeofModel);
|
|
GLModelHUDElement *hudElement = (GLModelHUDElement *)CALLOC(sizeofModel, 1);
|
|
if (hudElement) {
|
|
hudElement->colorScheme = RED_ON_BLACK;
|
|
}
|
|
return hudElement;
|
|
}
|
|
|
|
void glhud_setupDefault(GLModel *parent) {
|
|
|
|
GLModelHUDElement *hudElement = (GLModelHUDElement *)parent->custom;
|
|
char *submenu = (char *)(hudElement->tpl);
|
|
const unsigned int cols = hudElement->tplWidth;
|
|
const unsigned int rows = hudElement->tplHeight;
|
|
uint8_t *fb = hudElement->pixels;
|
|
|
|
// render template into indexed fb
|
|
interface_plotMessage(fb, hudElement->colorScheme, submenu, cols, rows);
|
|
|
|
// Generate OpenGL color from indexed color
|
|
const unsigned int fb_w = hudElement->pixWidth;
|
|
const unsigned int fb_h = hudElement->pixHeight;
|
|
const unsigned int count = fb_w * fb_h;
|
|
const unsigned int countOut = count * sizeof(PIXEL_TYPE);
|
|
for (unsigned int srcIdx=0, dstIdx=0; srcIdx<count; srcIdx++, dstIdx+=sizeof(PIXEL_TYPE)) {
|
|
uint8_t index = *(fb + srcIdx);
|
|
PIXEL_TYPE rgb = (((PIXEL_TYPE)(colormap[index].red) << SHIFT_R) |
|
|
((PIXEL_TYPE)(colormap[index].green) << SHIFT_G) |
|
|
((PIXEL_TYPE)(colormap[index].blue) << SHIFT_B));
|
|
if (rgb == 0 && hudElement->blackIsTransparent) {
|
|
// make black transparent
|
|
} else {
|
|
rgb |= ((PIXEL_TYPE)MAX_SATURATION << SHIFT_A);
|
|
}
|
|
*( (PIXEL_TYPE*)(parent->texPixels + dstIdx) ) = rgb;
|
|
}
|
|
|
|
// Second pass to generate a semi-opaque halo effect around each glyph
|
|
if (hudElement->opaquePixelHalo) {
|
|
for (int // -negative index values allowed here ...
|
|
srcIdx=0, dstPre=-((fb_w+1)*sizeof(PIXEL_TYPE)), dstIdx=0, dstPost=((fb_w-1)*sizeof(PIXEL_TYPE));
|
|
srcIdx<count;
|
|
srcIdx++, dstPre+=sizeof(PIXEL_TYPE), dstIdx+=sizeof(PIXEL_TYPE), dstPost+=sizeof(PIXEL_TYPE))
|
|
{
|
|
uint8_t index = *(fb + srcIdx);
|
|
PIXEL_TYPE rgb = (((PIXEL_TYPE)(colormap[index].red) << SHIFT_R) |
|
|
((PIXEL_TYPE)(colormap[index].green) << SHIFT_G) |
|
|
((PIXEL_TYPE)(colormap[index].blue) << SHIFT_B));
|
|
if (!rgb) {
|
|
continue;
|
|
}
|
|
|
|
#if USE_RGBA4444
|
|
#define SEMI_OPAQUE (0x0C << SHIFT_A)
|
|
#else
|
|
#define SEMI_OPAQUE (0xC0 << SHIFT_A)
|
|
#endif
|
|
const unsigned int col = (srcIdx % fb_w);
|
|
|
|
if (dstPre >= 0) { // north pixels
|
|
if (col != 0) {
|
|
*((PIXEL_TYPE*)(parent->texPixels + dstPre)) |= SEMI_OPAQUE;
|
|
}
|
|
*((PIXEL_TYPE*)(parent->texPixels + dstPre + sizeof(PIXEL_TYPE) )) |= SEMI_OPAQUE;
|
|
if (col < fb_w-1) {
|
|
*((PIXEL_TYPE*)(parent->texPixels + dstPre + (2*sizeof(PIXEL_TYPE)) )) |= SEMI_OPAQUE;
|
|
}
|
|
}
|
|
|
|
if (col != 0) { // west pixel
|
|
*((PIXEL_TYPE*)(parent->texPixels + dstIdx - sizeof(PIXEL_TYPE) )) |= SEMI_OPAQUE;
|
|
}
|
|
|
|
if (col < fb_w-1) { // east pixel
|
|
*((PIXEL_TYPE*)(parent->texPixels + dstIdx + sizeof(PIXEL_TYPE) )) |= SEMI_OPAQUE;
|
|
}
|
|
|
|
if (dstPost < countOut) { // south pixels
|
|
if (col != 0) {
|
|
*((PIXEL_TYPE*)(parent->texPixels + dstPost)) |= SEMI_OPAQUE;
|
|
}
|
|
*((PIXEL_TYPE*)(parent->texPixels + dstPost + sizeof(PIXEL_TYPE) )) |= SEMI_OPAQUE;
|
|
if (col < fb_w-1) {
|
|
*((PIXEL_TYPE*)(parent->texPixels + dstPost + (2*sizeof(PIXEL_TYPE)) )) |= SEMI_OPAQUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
parent->texDirty = true;
|
|
}
|
|
|
|
void glhud_renderDefault(GLModel *parent) {
|
|
|
|
// Bind our vertex array object
|
|
#if USE_VAO
|
|
glBindVertexArray(parent->vaoName);
|
|
#else
|
|
glBindBuffer(GL_ARRAY_BUFFER, parent->posBufferName);
|
|
|
|
GLsizei posTypeSize = getGLTypeSize(parent->positionType);
|
|
GLsizei texcoordTypeSize = getGLTypeSize(parent->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)
|
|
parent->positionSize, // How many elements are there per position?
|
|
parent->positionType, // What is the type of this data?
|
|
GL_FALSE, // Do we want to normalize this data (0-1 range for fixed-pont types)
|
|
parent->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, parent->texcoordBufferName);
|
|
glVertexAttribPointer(TEXCOORD_ATTRIB_IDX, // What attibute index will this array feed in the vertex shader (see buildProgram)
|
|
parent->texcoordSize, // How many elements are there per texture coord?
|
|
parent->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)
|
|
parent->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, parent->elementBufferName);
|
|
#endif
|
|
|
|
// Draw the object
|
|
_HACKAROUND_GLDRAW_PRE();
|
|
glDrawElements(parent->primType, parent->numElements, parent->elementType, 0);
|
|
GL_ERRLOG("glhudparent render");
|
|
}
|
|
|
|
void glhud_destroyDefault(GLModel *parent) {
|
|
GLModelHUDElement *hudElement = (GLModelHUDElement *)parent->custom;
|
|
if (!hudElement) {
|
|
return;
|
|
}
|
|
|
|
if (hudElement->tpl) {
|
|
FREE(hudElement->tpl);
|
|
}
|
|
|
|
if (hudElement->pixels) {
|
|
FREE(hudElement->pixels);
|
|
}
|
|
|
|
FREE(parent->custom);
|
|
}
|
|
|
|
void glhud_screenToModel(const float x, const float y, const int screenW, const int screenH, float *centerX, float *centerY) {
|
|
*centerX = (x/(screenW>>1))-1.f;
|
|
*centerY = ((screenH-y)/(screenH>>1))-1.f;
|
|
}
|
|
|
|
void glhud_quadModelToScreen(const GLModel *model, const int screenW, const int screenH, float screenCoords[4]) {
|
|
float x0 = 1.0;
|
|
float y0 = 1.0;
|
|
float x1 = -1.0;
|
|
float y1 = -1.0;
|
|
|
|
#warning NOTE: we possibly should use matrix calculations (but assuming HUD elements are identity/orthographic for now)
|
|
GLfloat *positions = (GLfloat *)(model->positions);
|
|
unsigned int stride = model->positionSize;
|
|
unsigned int len = model->positionArraySize/getGLTypeSize(model->positionType);
|
|
for (unsigned int i=0; i < len; i += stride) {
|
|
float x = (positions[i] + 1.f) / 2.f;
|
|
if (x < x0) {
|
|
x0 = x;
|
|
}
|
|
if (x > x1) {
|
|
x1 = x;
|
|
}
|
|
float y = (positions[i+1] + 1.f) / 2.f;
|
|
LOG("\tmodel x:%f, y:%f", x, y);
|
|
if (y < y0) {
|
|
y0 = y;
|
|
}
|
|
if (y > y1) {
|
|
y1 = y;
|
|
}
|
|
}
|
|
|
|
// OpenGL screen origin is bottom-left (Android is top-left)
|
|
float yFlip0 = screenH - (y1 * screenH);
|
|
float yFlip1 = screenH - (y0 * screenH);
|
|
|
|
screenCoords[0] = x0 * screenW;
|
|
screenCoords[1] = yFlip0;
|
|
screenCoords[2] = x1 * screenW;
|
|
screenCoords[3] = yFlip1;
|
|
}
|
|
|