2014-09-17 03:49:57 +00:00
/*
* 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
# include "common.h"
2015-03-23 01:53:13 +00:00
# include "video/glvideo.h"
2014-09-21 22:58:27 +00:00
# include "video/glinput.h"
2015-04-12 22:35:16 +00:00
# include "video/glnode.h"
2014-09-17 03:49:57 +00:00
2014-11-29 21:31:21 +00:00
bool safe_to_do_opengl_logging = false ;
2015-01-11 20:27:39 +00:00
volatile bool _vid_dirty = true ;
2014-09-17 03:49:57 +00:00
static int windowWidth = SCANWIDTH * 1.5 ;
static int windowHeight = SCANHEIGHT * 1.5 ;
static int viewportX = 0 ;
static int viewportY = 0 ;
static int viewportWidth = SCANWIDTH * 1.5 ;
static int viewportHeight = SCANHEIGHT * 1.5 ;
2015-03-11 19:54:50 +00:00
# if MOBILE_DEVICE
static int adjustedHeight = 0 ;
# endif
2014-09-17 03:49:57 +00:00
2015-03-23 01:53:13 +00:00
GLint uniformTex2Use = UNINITIALIZED_GL ;
GLint alphaValue = UNINITIALIZED_GL ;
static GLint uniformMVPIdx = UNINITIALIZED_GL ;
static GLenum crtElementType = UNINITIALIZED_GL ;
static GLuint crtNumElements = UNINITIALIZED_GL ;
2014-09-17 03:49:57 +00:00
2015-03-23 01:53:13 +00:00
static GLuint a2TextureName = UNINITIALIZED_GL ;
static GLuint defaultFBO = UNINITIALIZED_GL ;
static GLuint program = UNINITIALIZED_GL ;
2014-09-17 03:49:57 +00:00
2015-03-23 01:53:13 +00:00
static GLuint crtVAOName = UNINITIALIZED_GL ;
static GLuint posBufferName = UNINITIALIZED_GL ;
static GLuint texcoordBufferName = UNINITIALIZED_GL ;
static GLuint elementBufferName = UNINITIALIZED_GL ;
2015-04-10 05:49:53 +00:00
static GLModel * crtModel = NULL ;
2015-02-18 03:54:47 +00:00
2015-03-23 01:53:13 +00:00
# if USE_GLUT
static int glutWindow = - 1 ;
# endif
2014-09-17 03:49:57 +00:00
//----------------------------------------------------------------------------
//
2014-09-27 18:03:51 +00:00
// OpenGL helper routines
2014-09-17 03:49:57 +00:00
//
2015-02-18 03:54:47 +00:00
static void _create_CRT_model ( void ) {
2014-09-27 18:03:51 +00:00
// NOTE: vertices in Normalized Device Coordinates
const GLfloat crt_positions [ ] = {
// CRT screen quad
- 1.0 , - 1.0 , 0.0 , 1.0 ,
2015-03-23 01:53:13 +00:00
1.0 , - 1.0 , 0.0 , 1.0 ,
2014-09-27 18:03:51 +00:00
- 1.0 , 1.0 , 0.0 , 1.0 ,
2015-03-23 01:53:13 +00:00
1.0 , 1.0 , 0.0 , 1.0 ,
2014-09-27 18:03:51 +00:00
# if PERSPECTIVE
// CRT back side point
0.0 , 0.0 , - 1.0 , 1.0 ,
# endif
} ;
const GLfloat crt_texcoords [ ] = {
0.0 , 1.0 ,
1.0 , 1.0 ,
0.0 , 0.0 ,
1.0 , 0.0 ,
} ;
const GLushort indices [ ] = {
// CRT screen quad
0 , 1 , 2 , 2 , 1 , 3
# if PERSPECTIVE
// ...
# endif
} ;
2015-04-10 05:49:53 +00:00
GLModel * crt = calloc ( 1 , sizeof ( GLModel ) ) ;
2014-09-27 18:03:51 +00:00
crt - > numVertices = 4 ;
crt - > numElements = 6 ;
crt - > positions = malloc ( sizeof ( crt_positions ) ) ;
memcpy ( crt - > positions , & crt_positions [ 0 ] , sizeof ( crt_positions ) ) ;
crt - > positionType = GL_FLOAT ;
crt - > positionSize = 4 ; // x,y,z coordinates
crt - > positionArraySize = sizeof ( crt_positions ) ;
2015-04-11 07:30:23 +00:00
crt - > texCoords = malloc ( sizeof ( crt_texcoords ) ) ;
memcpy ( crt - > texCoords , & crt_texcoords [ 0 ] , sizeof ( crt_texcoords ) ) ;
2014-09-27 18:03:51 +00:00
crt - > texcoordType = GL_FLOAT ;
crt - > texcoordSize = 2 ; // s,t coordinates
crt - > texcoordArraySize = sizeof ( crt_texcoords ) ;
crt - > normals = NULL ;
crt - > normalType = GL_NONE ;
crt - > normalSize = GL_NONE ;
crt - > normalArraySize = 0 ;
crt - > elements = malloc ( sizeof ( indices ) ) ;
memcpy ( crt - > elements , & indices [ 0 ] , sizeof ( indices ) ) ;
crt - > elementType = GL_UNSIGNED_SHORT ;
crt - > elementArraySize = sizeof ( indices ) ;
2015-04-11 07:30:23 +00:00
mdlDestroyModel ( & crtModel ) ;
2015-02-18 03:54:47 +00:00
crtModel = crt ;
2014-09-27 18:03:51 +00:00
}
2015-02-18 03:54:47 +00:00
static void _create_VAO_VBOs ( void ) {
2014-09-27 18:03:51 +00:00
// Create a vertex array object (VAO) to cache model parameters
2015-02-18 03:54:47 +00:00
# if USE_VAO
glGenVertexArrays ( 1 , & crtVAOName ) ;
glBindVertexArray ( crtVAOName ) ;
# endif
2014-09-27 18:03:51 +00:00
// Create a vertex buffer object (VBO) to store positions and load data
glGenBuffers ( 1 , & posBufferName ) ;
glBindBuffer ( GL_ARRAY_BUFFER , posBufferName ) ;
2015-02-18 03:54:47 +00:00
glBufferData ( GL_ARRAY_BUFFER , crtModel - > positionArraySize , crtModel - > positions , GL_STATIC_DRAW ) ;
2014-09-27 18:03:51 +00:00
2015-02-18 03:54:47 +00:00
# if USE_VAO
2014-09-27 18:03:51 +00:00
// 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
2015-04-12 18:27:33 +00:00
GLsizei posTypeSize = getGLTypeSize ( crtModel - > positionType ) ;
2014-09-27 18:03:51 +00:00
// 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)
2015-02-18 03:54:47 +00:00
crtModel - > positionSize , // How many elements are there per position?
crtModel - > positionType , // What is the type of this data?
2014-09-27 18:03:51 +00:00
GL_FALSE , // Do we want to normalize this data (0-1 range for fixed-pont types)
2015-02-18 03:54:47 +00:00
crtModel - > positionSize * posTypeSize , // What is the stride (i.e. bytes between positions)?
2014-09-27 18:03:51 +00:00
0 ) ; // What is the offset in the VBO to the position data?
2015-02-18 03:54:47 +00:00
# endif
2014-09-27 18:03:51 +00:00
2015-04-11 07:30:23 +00:00
if ( crtModel - > texCoords ) {
2014-09-27 18:03:51 +00:00
// Create a VBO to store texcoords
glGenBuffers ( 1 , & texcoordBufferName ) ;
glBindBuffer ( GL_ARRAY_BUFFER , texcoordBufferName ) ;
// Allocate and load texcoord data into the VBO
2015-04-11 07:30:23 +00:00
glBufferData ( GL_ARRAY_BUFFER , crtModel - > texcoordArraySize , crtModel - > texCoords , GL_STATIC_DRAW ) ;
2014-09-27 18:03:51 +00:00
2015-02-18 03:54:47 +00:00
# if USE_VAO
2014-09-27 18:03:51 +00:00
// 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
2015-04-12 18:27:33 +00:00
GLsizei texcoordTypeSize = getGLTypeSize ( crtModel - > texcoordType ) ;
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
// 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)
2015-02-18 03:54:47 +00:00
crtModel - > texcoordSize , // How many elements are there per texture coord?
crtModel - > texcoordType , // What is the type of this data in the array?
2014-09-27 18:03:51 +00:00
GL_TRUE , // Do we want to normalize this data (0-1 range for fixed-point types)
2015-02-18 03:54:47 +00:00
crtModel - > texcoordSize * texcoordTypeSize , // What is the stride (i.e. bytes between texcoords)?
2014-09-27 18:03:51 +00:00
0 ) ; // What is the offset in the VBO to the texcoord data?
2015-02-18 03:54:47 +00:00
# endif
2014-09-17 03:49:57 +00:00
}
2014-09-27 18:03:51 +00:00
// 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
2015-02-18 03:54:47 +00:00
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , crtModel - > elementArraySize , crtModel - > elements , GL_STATIC_DRAW ) ;
2014-09-27 18:03:51 +00:00
2014-10-25 18:38:28 +00:00
GL_ERRLOG ( " finished creating VAO/VBOs " ) ;
2014-09-27 18:03:51 +00:00
}
static void _destroy_VAO ( GLuint vaoName ) {
// Bind the VAO so we can get data from it
2015-02-18 03:54:47 +00:00
# if USE_VAO
2014-09-27 18:03:51 +00:00
glBindVertexArray ( vaoName ) ;
// For every possible attribute set in the VAO
2014-12-21 21:59:04 +00:00
for ( GLuint index = 0 ; index < 16 ; index + + ) {
2014-09-27 18:03:51 +00:00
// Get the VBO set for that attibute
2014-12-21 21:59:04 +00:00
GLuint bufName = 0 ;
2014-09-27 18:03:51 +00:00
glGetVertexAttribiv ( index , GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING , ( GLint * ) & bufName ) ;
// If there was a VBO set...
if ( bufName ) {
//...delete the VBO
glDeleteBuffers ( 1 , & bufName ) ;
2014-09-17 03:49:57 +00:00
}
}
2014-09-27 18:03:51 +00:00
// Get any element array VBO set in the VAO
2014-12-21 21:59:04 +00:00
{
GLuint bufName = 0 ;
glGetIntegerv ( GL_ELEMENT_ARRAY_BUFFER_BINDING , ( GLint * ) & bufName ) ;
2014-09-27 18:03:51 +00:00
2014-12-21 21:59:04 +00:00
// If there was a element array VBO set in the VAO
if ( bufName ) {
//...delete the VBO
glDeleteBuffers ( 1 , & bufName ) ;
}
2014-09-27 18:03:51 +00:00
}
// Finally, delete the VAO
glDeleteVertexArrays ( 1 , & vaoName ) ;
2015-02-18 03:54:47 +00:00
# else
glDeleteBuffers ( 1 , & posBufferName ) ;
2015-03-23 01:53:13 +00:00
posBufferName = UNINITIALIZED_GL ;
2015-02-18 03:54:47 +00:00
glDeleteBuffers ( 1 , & texcoordBufferName ) ;
2015-03-23 01:53:13 +00:00
texcoordBufferName = UNINITIALIZED_GL ;
2015-02-18 03:54:47 +00:00
glDeleteBuffers ( 1 , & elementBufferName ) ;
2015-03-23 01:53:13 +00:00
elementBufferName = UNINITIALIZED_GL ;
2015-02-18 03:54:47 +00:00
# endif
2014-09-27 18:03:51 +00:00
GL_ERRLOG ( " destroying VAO/VBOs " ) ;
2014-09-17 03:49:57 +00:00
}
2014-09-27 18:03:51 +00:00
static GLuint _create_CRT_texture ( void ) {
GLuint texName ;
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
// Create a texture object to apply to model
glGenTextures ( 1 , & texName ) ;
2015-03-23 01:53:13 +00:00
glActiveTexture ( TEXTURE_ACTIVE_FRAMEBUFFER ) ;
2014-09-27 18:03:51 +00:00
glBindTexture ( GL_TEXTURE_2D , texName ) ;
// 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 ) ;
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
// 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 ) ;
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
// Allocate and load image data into texture
glTexImage2D ( GL_TEXTURE_2D , /*level*/ 0 , /*internal format*/ GL_RGBA , SCANWIDTH , SCANHEIGHT , /*border*/ 0 , /*format*/ GL_RGBA , GL_UNSIGNED_BYTE , NULL ) ;
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
GL_ERRLOG ( " finished creating CRT texture " ) ;
return texName ;
2014-09-17 03:49:57 +00:00
}
2014-09-27 18:03:51 +00:00
static GLuint _build_program ( demoSource * vertexSource , demoSource * fragmentSource , bool hasNormal , bool hasTexcoord ) {
GLuint prgName ;
GLint logLength , status ;
// String to pass to glShaderSource
GLchar * sourceString = NULL ;
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
// Determine if GLSL version 140 is supported by this context.
// We'll use this info to generate a GLSL shader source string
// with the proper version preprocessor string prepended
2015-02-25 04:53:19 +00:00
float glLanguageVersion = 0.f ;
2014-09-17 03:49:57 +00:00
2015-02-25 04:53:19 +00:00
char * shaderLangVersion = ( char * ) glGetString ( GL_SHADING_LANGUAGE_VERSION ) ;
if ( shaderLangVersion = = NULL ) {
ERRQUIT ( " shader toolchain unavailable " ) ;
}
2014-10-08 04:59:21 +00:00
# if TARGET_OS_IPHONE
2015-02-25 04:53:19 +00:00
sscanf ( shaderLangVersion , " OpenGL ES GLSL ES %f " , & glLanguageVersion ) ;
2014-09-27 18:03:51 +00:00
# else
2015-02-25 04:53:19 +00:00
sscanf ( shaderLangVersion , " %f " , & glLanguageVersion ) ;
2014-09-27 18:03:51 +00:00
# endif
// GL_SHADING_LANGUAGE_VERSION returns the version standard version form
// with decimals, but the GLSL version preprocessor directive simply
// uses integers (thus 1.10 should 110 and 1.40 should be 140, etc.)
// We multiply the floating point number by 100 to get a proper
// number for the GLSL preprocessor directive
GLuint version = 100 * glLanguageVersion ;
// Get the size of the version preprocessor string info so we know
// how much memory to allocate for our sourceString
const GLsizei versionStringSize = sizeof ( " #version 123 \n " ) ;
// Create a program object
prgName = glCreateProgram ( ) ;
// Indicate the attribute indicies on which vertex arrays will be
// set with glVertexAttribPointer
// See buildVAO to see where vertex arrays are actually set
glBindAttribLocation ( prgName , POS_ATTRIB_IDX , " inPosition " ) ;
if ( hasNormal ) {
glBindAttribLocation ( prgName , NORMAL_ATTRIB_IDX , " inNormal " ) ;
2014-09-17 03:49:57 +00:00
}
2014-09-27 18:03:51 +00:00
if ( hasTexcoord ) {
glBindAttribLocation ( prgName , TEXCOORD_ATTRIB_IDX , " inTexcoord " ) ;
}
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
//////////////////////////////////////
// Specify and compile VertexShader //
//////////////////////////////////////
// Allocate memory for the source string including the version preprocessor information
sourceString = malloc ( vertexSource - > byteSize + versionStringSize ) ;
// Prepend our vertex shader source string with the supported GLSL version so
// the shader will work on ES, Legacy, and OpenGL 3.2 Core Profile contexts
2015-03-10 00:01:17 +00:00
if ( version ) {
sprintf ( sourceString , " #version %d \n %s " , version , vertexSource - > string ) ;
} else {
RELEASE_LOG ( " YAY, you have an awesome OpenGL vendor for this device ... no GLSL version specified ... so NOT adding a #version directive to shader sources =P " ) ;
sprintf ( sourceString , " %s " , vertexSource - > string ) ;
}
2014-09-27 18:03:51 +00:00
GLuint vertexShader = glCreateShader ( GL_VERTEX_SHADER ) ;
glShaderSource ( vertexShader , 1 , ( const GLchar * * ) & ( sourceString ) , NULL ) ;
glCompileShader ( vertexShader ) ;
glGetShaderiv ( vertexShader , GL_INFO_LOG_LENGTH , & logLength ) ;
if ( logLength > 0 ) {
GLchar * log = ( GLchar * ) malloc ( logLength ) ;
glGetShaderInfoLog ( vertexShader , logLength , & logLength , log ) ;
LOG ( " Vtx Shader compile log:%s \n " , log ) ;
free ( log ) ;
}
glGetShaderiv ( vertexShader , GL_COMPILE_STATUS , & status ) ;
if ( status = = 0 ) {
LOG ( " Failed to compile vtx shader: \n %s \n " , sourceString ) ;
return 0 ;
}
free ( sourceString ) ;
sourceString = NULL ;
// Attach the vertex shader to our program
glAttachShader ( prgName , vertexShader ) ;
// Delete the vertex shader since it is now attached
// to the program, which will retain a reference to it
glDeleteShader ( vertexShader ) ;
/////////////////////////////////////////
// Specify and compile Fragment Shader //
/////////////////////////////////////////
// Allocate memory for the source string including the version preprocessor information
sourceString = malloc ( fragmentSource - > byteSize + versionStringSize ) ;
// Prepend our fragment shader source string with the supported GLSL version so
// the shader will work on ES, Legacy, and OpenGL 3.2 Core Profile contexts
2015-03-10 00:01:17 +00:00
if ( version ) {
sprintf ( sourceString , " #version %d \n %s " , version , fragmentSource - > string ) ;
} else {
sprintf ( sourceString , " %s " , fragmentSource - > string ) ;
}
2014-09-27 18:03:51 +00:00
GLuint fragShader = glCreateShader ( GL_FRAGMENT_SHADER ) ;
glShaderSource ( fragShader , 1 , ( const GLchar * * ) & ( sourceString ) , NULL ) ;
glCompileShader ( fragShader ) ;
glGetShaderiv ( fragShader , GL_INFO_LOG_LENGTH , & logLength ) ;
if ( logLength > 0 ) {
GLchar * log = ( GLchar * ) malloc ( logLength ) ;
glGetShaderInfoLog ( fragShader , logLength , & logLength , log ) ;
LOG ( " Frag Shader compile log: \n %s \n " , log ) ;
free ( log ) ;
}
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
glGetShaderiv ( fragShader , GL_COMPILE_STATUS , & status ) ;
if ( status = = 0 ) {
LOG ( " Failed to compile frag shader: \n %s \n " , sourceString ) ;
return 0 ;
}
free ( sourceString ) ;
sourceString = NULL ;
// Attach the fragment shader to our program
glAttachShader ( prgName , fragShader ) ;
// Delete the fragment shader since it is now attached
// to the program, which will retain a reference to it
glDeleteShader ( fragShader ) ;
//////////////////////
// Link the program //
//////////////////////
glLinkProgram ( prgName ) ;
glGetProgramiv ( prgName , GL_INFO_LOG_LENGTH , & logLength ) ;
if ( logLength > 0 ) {
GLchar * log = ( GLchar * ) malloc ( logLength ) ;
glGetProgramInfoLog ( prgName , logLength , & logLength , log ) ;
LOG ( " Program link log: \n %s \n " , log ) ;
free ( log ) ;
}
glGetProgramiv ( prgName , GL_LINK_STATUS , & status ) ;
if ( status = = 0 ) {
LOG ( " Failed to link program " ) ;
return 0 ;
}
glValidateProgram ( prgName ) ;
glGetProgramiv ( prgName , GL_INFO_LOG_LENGTH , & logLength ) ;
if ( logLength > 0 ) {
GLchar * log = ( GLchar * ) malloc ( logLength ) ;
glGetProgramInfoLog ( prgName , logLength , & logLength , log ) ;
LOG ( " Program validate log: \n %s \n " , log ) ;
free ( log ) ;
}
glGetProgramiv ( prgName , GL_VALIDATE_STATUS , & status ) ;
if ( status = = 0 ) {
LOG ( " Failed to validate program " ) ;
return 0 ;
}
glUseProgram ( prgName ) ;
///////////////////////////////////////
// Setup common program input points //
///////////////////////////////////////
2015-03-23 01:53:13 +00:00
GLint fbSamplerLoc = glGetUniformLocation ( prgName , " framebufferTexture " ) ;
if ( fbSamplerLoc < 0 ) {
LOG ( " OOPS, no framebufferTexture shader : %d " , fbSamplerLoc ) ;
} else {
glUniform1i ( fbSamplerLoc , TEXTURE_ID_FRAMEBUFFER ) ;
}
GLint messageSamplerLoc = glGetUniformLocation ( prgName , " messageTexture " ) ;
if ( messageSamplerLoc < 0 ) {
LOG ( " OOPS, no messageSamplerLoc shader : %d " , messageSamplerLoc ) ;
} else {
glUniform1i ( messageSamplerLoc , TEXTURE_ID_MESSAGE ) ;
}
2015-04-12 22:35:16 +00:00
# if INTERFACE_TOUCH
2015-04-02 02:59:38 +00:00
GLint axisSamplerLoc = glGetUniformLocation ( prgName , " axisTexture " ) ;
if ( axisSamplerLoc < 0 ) {
LOG ( " OOPS, no axisSamplerLoc shader : %d " , axisSamplerLoc ) ;
} else {
glUniform1i ( axisSamplerLoc , TEXTURE_ID_TOUCHJOY_AXIS ) ;
}
GLint buttonSamplerLoc = glGetUniformLocation ( prgName , " buttonTexture " ) ;
if ( buttonSamplerLoc < 0 ) {
LOG ( " OOPS, no buttonSamplerLoc shader : %d " , buttonSamplerLoc ) ;
} else {
glUniform1i ( buttonSamplerLoc , TEXTURE_ID_TOUCHJOY_BUTTON ) ;
}
# endif
2015-03-23 01:53:13 +00:00
uniformMVPIdx = glGetUniformLocation ( prgName , " modelViewProjectionMatrix " ) ;
if ( uniformMVPIdx < 0 ) {
LOG ( " OOPS, no modelViewProjectionMatrix in shader : %d " , uniformMVPIdx ) ;
}
2014-09-27 18:03:51 +00:00
2015-03-23 01:53:13 +00:00
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 ) ;
}
2014-09-27 18:03:51 +00:00
GL_ERRLOG ( " build program " ) ;
return prgName ;
2014-09-17 03:49:57 +00:00
}
2014-09-27 18:03:51 +00:00
static demoSource * _create_shader_source ( const char * fileName ) {
demoSource * src = NULL ;
2014-10-08 05:05:14 +00:00
# if defined(__APPLE__)
2014-09-27 18:03:51 +00:00
CFBundleRef mainBundle = CFBundleGetMainBundle ( ) ;
CFStringRef fileString = CFStringCreateWithCString ( /*allocator*/ NULL , fileName , CFStringGetSystemEncoding ( ) ) ;
CFURLRef fileURL = CFBundleCopyResourceURL ( mainBundle , fileString , NULL , NULL ) ;
CFRELEASE ( fileString ) ;
CFStringRef filePath = CFURLCopyFileSystemPath ( fileURL , kCFURLPOSIXPathStyle ) ;
CFRELEASE ( fileURL ) ;
src = srcLoadSource ( CFStringGetCStringPtr ( filePath , CFStringGetSystemEncoding ( ) ) ) ;
CFRELEASE ( filePath ) ;
2015-02-23 19:19:41 +00:00
# else
2014-10-08 05:05:14 +00:00
char * filePath = NULL ;
2015-02-23 19:19:41 +00:00
asprintf ( & filePath , " %s/shaders/%s " , data_dir , fileName ) ;
2014-10-08 05:05:14 +00:00
if ( filePath ) {
src = srcLoadSource ( filePath ) ;
free ( filePath ) ;
} else {
ERRLOG ( " OOPS Could not load shader from %s (%s) " , filePath , fileName ) ;
}
2014-09-27 18:03:51 +00:00
# endif
return src ;
}
2014-09-17 03:49:57 +00:00
2015-03-23 01:53:13 +00:00
static void gldriver_render ( void ) ;
2014-09-21 22:58:27 +00:00
static void gldriver_init_common ( void ) {
2014-09-27 18:03:51 +00:00
LOG ( " %s %s " , glGetString ( GL_RENDERER ) , glGetString ( GL_VERSION ) ) ;
2014-09-17 03:49:57 +00:00
2015-03-11 19:54:50 +00:00
if ( ! viewportWidth ) {
viewportWidth = 400 ;
}
if ( ! viewportHeight ) {
viewportHeight = 400 ;
}
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
// ----------------------------
// Create CRT model VAO/VBOs
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
// create CRT model
2015-02-18 03:54:47 +00:00
_create_CRT_model ( ) ;
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
// Build Vertex Buffer Objects (VBOs) and Vertex Array Object (VAOs) with our model data
2015-02-18 03:54:47 +00:00
_create_VAO_VBOs ( ) ;
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
// Cache the number of element and primType to use later in our glDrawElements calls
crtNumElements = crtModel - > numElements ;
crtElementType = crtModel - > elementType ;
2015-02-18 03:54:47 +00:00
# if USE_VAO
2015-04-17 04:49:39 +00:00
// We're using VAOs we can destroy certain buffers since they are already
2014-09-27 18:03:51 +00:00
// loaded into GL and we've saved anything else we need
2015-04-17 04:49:39 +00:00
FREE ( crtModel - > elements ) ;
FREE ( crtModel - > positions ) ;
FREE ( crtModel - > normals ) ;
FREE ( crtModel - > texCoords ) ;
2015-02-18 03:54:47 +00:00
# endif
2014-09-27 18:03:51 +00:00
// Build a default texture object with our image data
a2TextureName = _create_CRT_texture ( ) ;
// ----------------------------
// Load/setup shaders
2014-09-17 03:49:57 +00:00
2014-10-08 05:04:03 +00:00
demoSource * vtxSource = _create_shader_source ( " Basic.vsh " ) ;
demoSource * frgSource = _create_shader_source ( " Basic.fsh " ) ;
2014-09-27 18:03:51 +00:00
2014-11-22 22:08:53 +00:00
// Build/use Program
2014-09-27 18:03:51 +00:00
program = _build_program ( vtxSource , frgSource , /*withNormal:*/ false , /*withTexcoord:*/ true ) ;
srcDestroySource ( vtxSource ) ;
srcDestroySource ( frgSource ) ;
// ----------------------------
// setup static OpenGL state
// Depth test will always be enabled
glEnable ( GL_DEPTH_TEST ) ;
// We will always cull back faces for better performance
glEnable ( GL_CULL_FACE ) ;
// Always use this clear color
2015-03-23 01:53:13 +00:00
glClearColor ( 0.0f , 0.0f , 0.0f , 0.0f ) ;
glEnable ( GL_BLEND ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2014-09-27 18:03:51 +00:00
// 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
2015-03-23 01:53:13 +00:00
gldriver_render ( ) ;
2014-09-27 18:03:51 +00:00
// Check for errors to make sure all of our setup went ok
GL_ERRLOG ( " finished initialization " ) ;
2014-10-08 05:05:14 +00:00
# if !defined(__APPLE__)
2014-11-22 22:08:53 +00:00
//glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
2014-10-08 05:05:14 +00:00
# endif
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) {
ERRQUIT ( " framebuffer status: %04X " , status ) ;
}
2014-09-27 18:03:51 +00:00
}
static void gldriver_shutdown ( void ) {
2015-03-23 01:53:13 +00:00
# if USE_GLUT
glutDestroyWindow ( glutWindow ) ;
# endif
2014-09-27 18:03:51 +00:00
// Cleanup all OpenGL objects
glDeleteTextures ( 1 , & a2TextureName ) ;
2015-03-23 01:53:13 +00:00
a2TextureName = UNINITIALIZED_GL ;
2014-09-27 18:03:51 +00:00
_destroy_VAO ( crtVAOName ) ;
2015-03-23 01:53:13 +00:00
crtVAOName = UNINITIALIZED_GL ;
2015-04-11 07:30:23 +00:00
mdlDestroyModel ( & crtModel ) ;
2014-09-27 18:03:51 +00:00
glDeleteProgram ( program ) ;
2015-03-23 01:53:13 +00:00
program = UNINITIALIZED_GL ;
2015-04-12 22:35:16 +00:00
glnode_shutdownNodes ( ) ;
2014-09-17 03:49:57 +00:00
}
//----------------------------------------------------------------------------
//
2014-09-27 18:03:51 +00:00
// update, render, reshape
2014-09-17 03:49:57 +00:00
//
2014-10-25 17:18:22 +00:00
# if USE_GLUT
2015-01-15 07:17:50 +00:00
static void gldriver_update ( int unused ) {
2015-01-18 19:10:16 +00:00
# if DEBUG_GL
static uint32_t prevCount = 0 ;
static uint32_t idleCount = 0 ;
idleCount + + ;
static struct timespec prev = { 0 } ;
struct timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
if ( now . tv_sec ! = prev . tv_sec ) {
LOG ( " gldriver_update() : %u " , idleCount - prevCount ) ;
prevCount = idleCount ;
prev = now ;
}
# endif
2014-09-22 00:26:37 +00:00
c_keys_handle_input ( - 1 , 0 , 0 ) ;
2015-02-25 04:53:19 +00:00
glutPostRedisplay ( ) ;
2015-01-15 07:17:50 +00:00
glutTimerFunc ( 17 , gldriver_update , 0 ) ;
2014-09-17 03:49:57 +00:00
}
2014-10-25 17:18:22 +00:00
# endif
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
static void gldriver_render ( void ) {
2015-01-24 07:37:43 +00:00
const uint8_t * const fb = video_current_framebuffer ( ) ;
if ( UNLIKELY ( ! fb ) ) {
return ;
}
2014-09-27 18:03:51 +00:00
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
2015-03-11 19:54:50 +00:00
# if MOBILE_DEVICE
glViewport ( viewportX , adjustedHeight , viewportWidth , viewportHeight ) ;
# endif
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
# if PERSPECTIVE
// Calculate modelview and projection matrices
GLfloat modelView [ 16 ] ;
GLfloat projection [ 16 ] ;
mtxLoadPerspective ( projection , 90 , ( float ) viewportWidth / ( float ) viewportHeight , 5.0 , 10000 ) ;
# endif
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
// Calculate the modelview matrix to render our character
// at the proper position and rotation
GLfloat mvp [ 16 ] ;
# if PERSPECTIVE
// Create model-view-projection matrix
//mtxLoadTranslate(modelView, 0, 150, -450);
//mtxRotateXApply(modelView, -90.0f);
//mtxRotateApply(modelView, -45.0f, 0.7, 0.3, 1);
mtxMultiply ( mvp , projection , modelView ) ;
# else
// Just load an identity matrix for a pure orthographic/non-perspective viewing
mtxLoadIdentity ( mvp ) ;
2014-09-17 03:49:57 +00:00
# endif
2014-09-27 18:03:51 +00:00
// Have our shader use the modelview projection matrix
// that we calculated above
glUniformMatrix4fv ( uniformMVPIdx , 1 , GL_FALSE , mvp ) ;
2014-09-17 03:49:57 +00:00
char pixels [ SCANWIDTH * SCANHEIGHT * 4 ] ;
2015-02-25 04:53:19 +00:00
if ( _vid_dirty ) {
// Update texture from indexed-color Apple //e internal framebuffer
unsigned int count = SCANWIDTH * SCANHEIGHT ;
for ( unsigned int i = 0 , j = 0 ; i < count ; i + + , j + = 4 ) {
uint8_t index = * ( fb + i ) ;
* ( ( uint32_t * ) ( pixels + 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 )
) ;
}
2014-09-17 03:49:57 +00:00
}
2015-03-23 01:53:13 +00:00
glActiveTexture ( TEXTURE_ACTIVE_FRAMEBUFFER ) ;
2014-09-27 18:03:51 +00:00
glBindTexture ( GL_TEXTURE_2D , a2TextureName ) ;
2015-03-23 01:53:13 +00:00
glUniform1i ( uniformTex2Use , TEXTURE_ID_FRAMEBUFFER ) ;
2015-02-25 04:53:19 +00:00
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 ] ) ;
}
2014-09-17 03:49:57 +00:00
2014-09-27 18:03:51 +00:00
// Bind our vertex array object
2015-02-18 03:54:47 +00:00
# if USE_VAO
2014-09-27 18:03:51 +00:00
glBindVertexArray ( crtVAOName ) ;
2015-02-18 03:54:47 +00:00
# else
glBindBuffer ( GL_ARRAY_BUFFER , posBufferName ) ;
2015-04-12 18:27:33 +00:00
GLsizei posTypeSize = getGLTypeSize ( crtModel - > positionType ) ;
GLsizei texcoordTypeSize = getGLTypeSize ( crtModel - > texcoordType ) ;
2015-02-18 03:54:47 +00:00
// 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)
crtModel - > positionSize , // How many elements are there per position?
crtModel - > positionType , // What is the type of this data?
GL_FALSE , // Do we want to normalize this data (0-1 range for fixed-pont types)
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 ) ;
// 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
2015-03-23 01:53:13 +00:00
glBindBuffer ( GL_ARRAY_BUFFER , texcoordBufferName ) ;
2015-02-18 03:54:47 +00:00
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?
GL_TRUE , // Do we want to normalize this data (0-1 range for fixed-point types)
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 ) ;
2015-03-23 01:53:13 +00:00
2015-02-18 03:54:47 +00:00
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , elementBufferName ) ;
# endif
2014-09-27 18:03:51 +00:00
2015-03-23 01:53:13 +00:00
glUniform1f ( alphaValue , 1.0 ) ;
2014-09-27 18:03:51 +00:00
// Cull back faces now that we no longer render
// with an inverted matrix
2015-03-23 01:53:13 +00:00
//glCullFace(GL_BACK);
2014-09-17 03:49:57 +00:00
2015-03-23 01:53:13 +00:00
// Draw the CRT object and others
2014-09-27 18:03:51 +00:00
glDrawElements ( GL_TRIANGLES , crtNumElements , crtElementType , 0 ) ;
2014-10-08 05:05:14 +00:00
2015-04-12 22:35:16 +00:00
// Render HUD nodes
glnode_renderNodes ( ) ;
2015-03-23 01:53:13 +00:00
2015-01-11 20:27:39 +00:00
_vid_dirty = false ;
2014-10-08 05:05:14 +00:00
# if USE_GLUT
glutSwapBuffers ( ) ;
# endif
2015-03-23 01:53:13 +00:00
GL_ERRLOG ( " gldriver_render " ) ;
2014-09-17 03:49:57 +00:00
}
2014-09-21 22:58:27 +00:00
static void gldriver_reshape ( int w , int h ) {
2014-09-27 18:03:51 +00:00
//LOG("reshape to w:%d h:%d", w, h);
2014-09-17 03:49:57 +00:00
windowWidth = w ;
windowHeight = h ;
2015-03-11 19:54:50 +00:00
# if MOBILE_DEVICE
int viewportHeightPrevious = viewportHeight ;
# endif
2014-09-17 03:49:57 +00:00
int w2 = ( ( float ) h * ( SCANWIDTH / ( float ) SCANHEIGHT ) ) ;
int h2 = ( ( float ) w / ( SCANWIDTH / ( float ) SCANHEIGHT ) ) ;
if ( w2 < = w ) {
// h is priority
viewportX = ( w - w2 ) / 2 ;
viewportY = 0 ;
viewportWidth = w2 ;
viewportHeight = h ;
2014-09-27 18:03:51 +00:00
//LOG("OK1 : x:%d,y:%d w:%d,h:%d", viewportX, viewportY, viewportWidth, viewportHeight);
2014-09-17 03:49:57 +00:00
} else if ( h2 < = h ) {
viewportX = 0 ;
viewportY = ( h - h2 ) / 2 ;
viewportWidth = w ;
viewportHeight = h2 ;
2014-09-27 18:03:51 +00:00
//LOG("OK2 : x:%d,y:%d w:%d,h:%d", viewportX, viewportY, viewportWidth, viewportHeight);
2014-09-17 03:49:57 +00:00
} else {
viewportX = 0 ;
viewportY = 0 ;
viewportWidth = w ;
viewportHeight = h ;
2014-09-27 18:03:51 +00:00
//LOG("small viewport : x:%d,y:%d w:%d,h:%d", viewportX, viewportY, viewportWidth, viewportHeight);
2014-09-17 03:49:57 +00:00
}
2015-03-11 19:54:50 +00:00
# if MOBILE_DEVICE
if ( viewportHeight < viewportHeightPrevious ) {
adjustedHeight = viewportHeightPrevious - viewportHeight ;
} else {
adjustedHeight = 0 ;
}
# endif
2014-09-27 18:03:51 +00:00
glViewport ( viewportX , viewportY , viewportWidth , viewportHeight ) ;
2015-04-02 02:59:38 +00:00
2015-04-12 22:35:16 +00:00
// Reshape HUD nodes
glnode_reshapeNodes ( w , h ) ;
2014-09-17 03:49:57 +00:00
}
2014-09-27 18:03:51 +00:00
# if USE_GLUT
2014-10-08 05:05:14 +00:00
static void gldriver_init_glut ( GLuint fbo ) {
2014-09-17 03:49:57 +00:00
glutInit ( & argc , argv ) ;
2014-09-27 18:03:51 +00:00
glutInitDisplayMode ( /*GLUT_DOUBLE|*/ GLUT_RGBA | GLUT_DEPTH ) ;
2014-09-17 03:49:57 +00:00
glutInitWindowSize ( windowWidth , windowHeight ) ;
//glutInitContextVersion(4, 0); -- Is this needed?
glutInitContextProfile ( GLUT_CORE_PROFILE ) ;
2014-12-21 21:51:45 +00:00
glutWindow = glutCreateWindow ( PACKAGE_NAME ) ;
2014-09-17 03:49:57 +00:00
GL_ERRQUIT ( " GLUT initialization " ) ;
if ( glewInit ( ) ) {
ERRQUIT ( " Unable to initialize GLEW " ) ;
}
2014-09-21 22:58:27 +00:00
gldriver_init_common ( ) ;
2014-09-17 03:49:57 +00:00
2015-01-15 07:17:50 +00:00
glutTimerFunc ( 16 , gldriver_update , 0 ) ;
2014-09-27 18:03:51 +00:00
glutDisplayFunc ( gldriver_render ) ;
2014-09-21 22:58:27 +00:00
glutReshapeFunc ( gldriver_reshape ) ;
2014-09-17 03:49:57 +00:00
2015-02-16 02:32:45 +00:00
# if !TESTING
2014-09-21 22:58:27 +00:00
glutKeyboardFunc ( gldriver_on_key_down ) ;
glutKeyboardUpFunc ( gldriver_on_key_up ) ;
glutSpecialFunc ( gldriver_on_key_special_down ) ;
glutSpecialUpFunc ( gldriver_on_key_special_up ) ;
2014-11-22 22:08:53 +00:00
//glutMouseFunc(gldriver_mouse);
//glutMotionFunc(gldriver_mouse_drag);
2014-09-17 03:49:57 +00:00
# endif
2014-09-27 18:03:51 +00:00
}
# endif
//----------------------------------------------------------------------------
2015-03-23 01:53:13 +00:00
// backend renderer API
2014-09-27 18:03:51 +00:00
2015-03-23 01:53:13 +00:00
static void gldriver_init ( void * fbo ) {
2014-11-29 21:31:21 +00:00
safe_to_do_opengl_logging = true ;
2014-10-31 17:53:10 +00:00
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
2014-09-27 18:03:51 +00:00
defaultFBO = ( GLuint ) fbo ;
2014-10-31 17:53:10 +00:00
# pragma GCC diagnostic pop
2014-09-27 18:03:51 +00:00
# if defined(__APPLE__)
gldriver_init_common ( ) ;
2015-02-18 03:54:47 +00:00
# elif defined(ANDROID)
gldriver_init_common ( ) ;
2014-09-27 18:03:51 +00:00
# elif USE_GLUT
2014-10-25 15:44:21 +00:00
gldriver_init_glut ( defaultFBO ) ;
2014-09-27 18:03:51 +00:00
# else
# error no working codepaths
# endif
2015-04-12 22:35:16 +00:00
glnode_setupNodes ( ) ;
2014-09-17 03:49:57 +00:00
}
2015-03-23 01:53:13 +00:00
static void gldriver_main_loop ( void ) {
2014-09-27 18:03:51 +00:00
# if USE_GLUT
2014-09-17 03:49:57 +00:00
glutMainLoop ( ) ;
2014-09-27 18:03:51 +00:00
# endif
2015-03-23 01:53:13 +00:00
// fall through if not GLUT
2014-09-27 18:03:51 +00:00
}
2015-04-17 04:22:47 +00:00
video_backend_s * video_backendInstance ( void ) {
static video_backend_s * glvideo_backend = NULL ;
spin_lock_t lock = 0L ;
spin_lock_lock ( & lock ) ;
if ( glvideo_backend = = NULL ) {
glvideo_backend = malloc ( sizeof ( video_backend_s ) ) ;
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 ;
}
spin_lock_unlock ( & lock ) ;
return glvideo_backend ;
2014-09-17 03:49:57 +00:00
}
2014-11-22 22:08:53 +00:00