2014-09-27 18:03:51 +00:00
|
|
|
/*
|
2015-10-22 05:13:26 +00:00
|
|
|
* Apple // emulator for *ix
|
2014-10-08 04:59:21 +00:00
|
|
|
*
|
|
|
|
* This software package is subject to the GNU General Public License
|
2015-10-22 05:13:26 +00:00
|
|
|
* version 3 or later (your choice) as published by the Free Software
|
2014-10-08 04:59:21 +00:00
|
|
|
* Foundation.
|
|
|
|
*
|
2015-10-22 05:13:26 +00:00
|
|
|
* Copyright 2013-2015 Aaron Culliney
|
2014-10-08 04:59:21 +00:00
|
|
|
*
|
2014-09-27 18:03:51 +00:00
|
|
|
*/
|
|
|
|
|
2014-10-08 04:59:21 +00:00
|
|
|
// Based on sample code from https://developer.apple.com/library/mac/samplecode/GLEssentials/Introduction/Intro.html
|
|
|
|
|
2014-09-27 18:03:51 +00:00
|
|
|
#include "sourceUtil.h"
|
2016-01-02 18:53:28 +00:00
|
|
|
#include "modelUtil.h"
|
2014-09-27 18:03:51 +00:00
|
|
|
|
2016-01-02 18:53:28 +00:00
|
|
|
static demoSource *srcLoadSource(const char *filepathname) {
|
2015-12-31 06:16:57 +00:00
|
|
|
demoSource *source = (demoSource *)CALLOC(sizeof(demoSource), 1);
|
2014-10-08 04:59:21 +00:00
|
|
|
|
|
|
|
// Check the file name suffix to determine what type of shader this is
|
|
|
|
const char *suffixBegin = filepathname + strlen(filepathname) - 4;
|
|
|
|
|
|
|
|
if (!strncmp(suffixBegin, ".fsh", 4)) {
|
|
|
|
source->shaderType = GL_FRAGMENT_SHADER;
|
|
|
|
} else if (!strncmp(suffixBegin, ".vsh", 4)) {
|
|
|
|
source->shaderType = GL_VERTEX_SHADER;
|
|
|
|
} else {
|
|
|
|
// Unknown suffix
|
|
|
|
source->shaderType = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE *curFile = fopen(filepathname, "r");
|
2016-08-21 21:18:14 +00:00
|
|
|
if (!curFile) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-10-08 04:59:21 +00:00
|
|
|
|
|
|
|
// Get the size of the source
|
|
|
|
fseek(curFile, 0, SEEK_END);
|
2014-10-25 17:18:22 +00:00
|
|
|
GLsizei fileSize = (GLsizei)ftell(curFile);
|
2014-10-08 04:59:21 +00:00
|
|
|
|
|
|
|
// Add 1 to the file size to include the null terminator for the string
|
|
|
|
source->byteSize = fileSize + 1;
|
|
|
|
|
|
|
|
// Alloc memory for the string
|
2015-12-31 06:16:57 +00:00
|
|
|
source->string = MALLOC(source->byteSize);
|
2014-10-08 04:59:21 +00:00
|
|
|
|
|
|
|
// Read entire file into the string from beginning of the file
|
|
|
|
fseek(curFile, 0, SEEK_SET);
|
|
|
|
fread(source->string, 1, fileSize, curFile);
|
|
|
|
|
|
|
|
fclose(curFile);
|
|
|
|
|
|
|
|
// Insert null terminator
|
|
|
|
source->string[fileSize] = 0;
|
|
|
|
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
|
2016-01-02 18:53:28 +00:00
|
|
|
demoSource *glshader_createSource(const char *fileName) {
|
|
|
|
demoSource *src = NULL;
|
|
|
|
#if defined(__APPLE__)
|
|
|
|
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);
|
|
|
|
#else
|
|
|
|
char *filePath = NULL;
|
2016-02-26 05:43:54 +00:00
|
|
|
ASPRINTF(&filePath, "%s/shaders/%s", data_dir, fileName);
|
2016-01-02 18:53:28 +00:00
|
|
|
if (filePath) {
|
|
|
|
src = srcLoadSource(filePath);
|
2016-02-26 05:43:54 +00:00
|
|
|
FREE(filePath);
|
2016-01-02 18:53:28 +00:00
|
|
|
} else {
|
|
|
|
ERRLOG("OOPS Could not load shader from %s (%s)", filePath, fileName);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return src;
|
|
|
|
}
|
|
|
|
|
|
|
|
void glshader_destroySource(demoSource *source) {
|
2015-12-31 06:16:57 +00:00
|
|
|
FREE(source->string);
|
|
|
|
FREE(source);
|
2014-09-27 18:03:51 +00:00
|
|
|
}
|
|
|
|
|
2016-01-02 21:10:02 +00:00
|
|
|
GLuint glshader_buildProgram(demoSource *vertexSource, demoSource *fragmentSource, /*bool hasNormal, */bool hasTexcoord, OUTPARM GLuint *vertexShader, OUTPARM GLuint *fragShader) {
|
2016-01-02 18:53:28 +00:00
|
|
|
GLuint prgName = UNINITIALIZED_GL;
|
|
|
|
GLint logLength = UNINITIALIZED_GL;
|
|
|
|
GLint status = UNINITIALIZED_GL;
|
|
|
|
|
|
|
|
// String to pass to glShaderSource
|
|
|
|
GLchar *sourceString = NULL;
|
|
|
|
|
|
|
|
// 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
|
|
|
|
float glLanguageVersion = 0.f;
|
|
|
|
|
|
|
|
char *shaderLangVersion = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
|
|
|
|
if (shaderLangVersion == NULL) {
|
|
|
|
ERRQUIT("shader toolchain unavailable");
|
|
|
|
}
|
|
|
|
#if TARGET_OS_IPHONE
|
|
|
|
sscanf(shaderLangVersion, "OpenGL ES GLSL ES %f", &glLanguageVersion);
|
|
|
|
#else
|
|
|
|
sscanf(shaderLangVersion, "%f", &glLanguageVersion);
|
|
|
|
#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");
|
|
|
|
|
2016-01-02 21:10:02 +00:00
|
|
|
#if 0
|
2016-01-02 18:53:28 +00:00
|
|
|
if (hasNormal) {
|
|
|
|
glBindAttribLocation(prgName, NORMAL_ATTRIB_IDX, "inNormal");
|
|
|
|
}
|
2016-01-02 21:10:02 +00:00
|
|
|
#endif
|
2016-01-02 18:53:28 +00:00
|
|
|
|
|
|
|
if (hasTexcoord) {
|
|
|
|
glBindAttribLocation(prgName, TEXCOORD_ATTRIB_IDX, "inTexcoord");
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////
|
|
|
|
// 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
|
|
|
|
if (version) {
|
|
|
|
sprintf(sourceString, "#version %d\n%s", version, vertexSource->string);
|
|
|
|
} else {
|
|
|
|
RELEASE_LOG("No GLSL version specified ... so NOT adding a #version directive to shader sources =P");
|
|
|
|
sprintf(sourceString, "%s", vertexSource->string);
|
|
|
|
}
|
|
|
|
|
|
|
|
*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);
|
|
|
|
|
|
|
|
// Attach the vertex shader to our program
|
|
|
|
glAttachShader(prgName, *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
|
|
|
|
if (version) {
|
|
|
|
sprintf(sourceString, "#version %d\n%s", version, fragmentSource->string);
|
|
|
|
} else {
|
|
|
|
sprintf(sourceString, "%s", fragmentSource->string);
|
|
|
|
}
|
|
|
|
|
|
|
|
*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);
|
|
|
|
}
|
|
|
|
|
|
|
|
glGetShaderiv(*fragShader, GL_COMPILE_STATUS, &status);
|
|
|
|
if (status == 0) {
|
|
|
|
LOG("Failed to compile frag shader:\n%s\n", sourceString);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
FREE(sourceString);
|
|
|
|
|
|
|
|
// Attach the fragment shader to our program
|
|
|
|
glAttachShader(prgName, *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;
|
|
|
|
}
|
|
|
|
|
|
|
|
GL_ERRLOG("build program");
|
|
|
|
return prgName;
|
|
|
|
}
|
|
|
|
|