Last active
February 22, 2021 14:03
-
-
Save traysr/352a7df6f0322156c26b07ac6d74cf88 to your computer and use it in GitHub Desktop.
iOS Setup for bookofshaders.com
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifdef GL_ES | |
precision mediump float; | |
#endif | |
#define TWO_PI 6.28318530718 | |
uniform vec2 u_resolution; | |
uniform float u_time; | |
uniform vec2 u_mouse; | |
// Function from Iñigo Quiles | |
// https://www.shadertoy.com/view/MsS3Wc | |
vec3 hsb2rgb( in vec3 c ){ | |
vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0), | |
6.0)-3.0)-1.0, | |
0.0, | |
1.0 ); | |
rgb = rgb*rgb*(3.0-2.0*rgb); | |
return c.z * mix( vec3(1.0), rgb, c.y); | |
} | |
void main(){ | |
if (length(u_mouse) > 0.0 && length(gl_FragCoord.xy - u_mouse) < 50.0) { | |
gl_FragColor = vec4(1.0,1.0,1.0,1.0); | |
return; | |
} | |
vec2 st = gl_FragCoord.xy/u_resolution; | |
vec3 color = vec3(0.0); | |
// Use polar coordinates instead of cartesian | |
vec2 toCenter = vec2(0.5)-st; | |
float angle = atan(toCenter.y,toCenter.x); | |
float radius = length(toCenter)*2.0; | |
// Map the angle (-PI to PI) to the Hue (from 0 to 1) | |
// and the Saturation to the radius | |
color = hsb2rgb(vec3((angle/TWO_PI)+0.5,radius,1.0)); | |
gl_FragColor = vec4(color,1.0); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Shader.vsh | |
// GLTest | |
// | |
// Created by Satyakam Khadilkar on 12/13/16. | |
// Copyright © 2016 Satyakam Khadilkar. All rights reserved. | |
// | |
attribute vec4 position; | |
void main() | |
{ | |
gl_Position = position; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ShaderTestViewController.swift | |
// | |
// Created by Satyakam Khadilkar on 12/13/16. | |
// Copyright © 2016 Satyakam Khadilkar. All rights reserved. | |
// | |
import GLKit | |
import OpenGLES | |
func BUFFER_OFFSET(_ i: Int) -> UnsafeRawPointer { | |
return UnsafeRawPointer(bitPattern: i)! | |
} | |
let U_RESOLUTION = 0 | |
let U_MOUSE = 1 | |
let U_TIME = 2 | |
var uniforms = [GLint](repeating: 0, count: 3) | |
class ShaderTestViewController: GLKViewController, UIGestureRecognizerDelegate { | |
var program: GLuint = 0 | |
var resolution:GLKVector2 = GLKVector2() | |
var mouse:GLKVector2 = GLKVector2() | |
var time:GLfloat = 0.0 | |
var vertexArray: GLuint = 0 | |
var vertexBuffer: GLuint = 0 | |
var context: EAGLContext? = nil | |
deinit { | |
self.tearDownGL() | |
if EAGLContext.current() === self.context { | |
EAGLContext.setCurrent(nil) | |
} | |
} | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
self.context = EAGLContext(api: .openGLES2) | |
if !(self.context != nil) { | |
print("Failed to create ES context") | |
} | |
let view = self.view as! GLKView | |
view.context = self.context! | |
view.drawableDepthFormat = .formatNone | |
self.setupGL() | |
let recognizer = UIPanGestureRecognizer(target: self, action:#selector(ShaderTestViewController.handlePan(_:))) | |
recognizer.delegate = self | |
view.addGestureRecognizer(recognizer) | |
} | |
override func didReceiveMemoryWarning() { | |
super.didReceiveMemoryWarning() | |
if self.isViewLoaded && (self.view.window != nil) { | |
self.view = nil | |
self.tearDownGL() | |
if EAGLContext.current() === self.context { | |
EAGLContext.setCurrent(nil) | |
} | |
self.context = nil | |
} | |
} | |
func setupGL() { | |
EAGLContext.setCurrent(self.context) | |
if(self.loadShaders() == false) { | |
print("Failed to load shaders") | |
} | |
glGenVertexArraysOES(1, &vertexArray) | |
glBindVertexArrayOES(vertexArray) | |
glGenBuffers(1, &vertexBuffer) | |
glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertexBuffer) | |
glBufferData(GLenum(GL_ARRAY_BUFFER), GLsizeiptr(MemoryLayout<GLfloat>.size * gCubeVertexData.count), &gCubeVertexData, GLenum(GL_STATIC_DRAW)) | |
glEnableVertexAttribArray(GLuint(GLKVertexAttrib.position.rawValue)) | |
glVertexAttribPointer(GLuint(GLKVertexAttrib.position.rawValue), 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, nil) | |
glBindVertexArrayOES(0) | |
self.preferredFramesPerSecond = 60; | |
} | |
func tearDownGL() { | |
EAGLContext.setCurrent(self.context) | |
glDeleteBuffers(1, &vertexBuffer) | |
glDeleteVertexArraysOES(1, &vertexArray) | |
if program != 0 { | |
glDeleteProgram(program) | |
program = 0 | |
} | |
} | |
// MARK: - GLKView and GLKViewController delegate methods | |
func update() { | |
let scale = UIScreen.main.nativeScale | |
resolution = GLKVector2Make(Float(self.view.bounds.size.width*scale), Float(self.view.bounds.size.height*scale)) | |
time = Float(self.timeSinceFirstResume) | |
} | |
override func glkView(_ view: GLKView, drawIn rect: CGRect) { | |
glClearColor(0.65, 0.65, 0.65, 1.0) | |
glClear(GLbitfield(GL_COLOR_BUFFER_BIT)) | |
glBindVertexArrayOES(vertexArray) | |
// Render the object again with ES2 | |
glUseProgram(program) | |
glUniform2f(uniforms[U_RESOLUTION], resolution.x, resolution.y) | |
glUniform2f(uniforms[U_MOUSE], mouse.x, mouse.y) | |
glUniform1f(uniforms[U_TIME], time) | |
glDrawArrays(GLenum(GL_TRIANGLES), 0, 6) | |
} | |
// MARK: - OpenGL ES 2 shader compilation | |
func loadShaders() -> Bool { | |
var vertShader: GLuint = 0 | |
var fragShader: GLuint = 0 | |
var vertShaderPathname: String | |
var fragShaderPathname: String | |
// Create shader program. | |
program = glCreateProgram() | |
// Create and compile vertex shader. | |
vertShaderPathname = Bundle.main.path(forResource: "Shader", ofType: "vsh")! | |
if self.compileShader(&vertShader, type: GLenum(GL_VERTEX_SHADER), file: vertShaderPathname) == false { | |
print("Failed to compile vertex shader") | |
return false | |
} | |
// Create and compile fragment shader. | |
fragShaderPathname = Bundle.main.path(forResource: "Shader", ofType: "fsh")! | |
if !self.compileShader(&fragShader, type: GLenum(GL_FRAGMENT_SHADER), file: fragShaderPathname) { | |
print("Failed to compile fragment shader") | |
return false | |
} | |
// Attach vertex shader to program. | |
glAttachShader(program, vertShader) | |
// Attach fragment shader to program. | |
glAttachShader(program, fragShader) | |
// Bind attribute locations. | |
// This needs to be done prior to linking. | |
glBindAttribLocation(program, GLuint(GLKVertexAttrib.position.rawValue), "position") | |
// Link program. | |
if !self.linkProgram(program) { | |
print("Failed to link program: \(program)") | |
if vertShader != 0 { | |
glDeleteShader(vertShader) | |
vertShader = 0 | |
} | |
if fragShader != 0 { | |
glDeleteShader(fragShader) | |
fragShader = 0 | |
} | |
if program != 0 { | |
glDeleteProgram(program) | |
program = 0 | |
} | |
return false | |
} | |
// Get uniform locations. | |
uniforms[U_RESOLUTION] = glGetUniformLocation(program, "u_resolution") | |
uniforms[U_MOUSE] = glGetUniformLocation(program, "u_mouse") | |
uniforms[U_TIME] = glGetUniformLocation(program, "u_time") | |
// Release vertex and fragment shaders. | |
if vertShader != 0 { | |
glDetachShader(program, vertShader) | |
glDeleteShader(vertShader) | |
} | |
if fragShader != 0 { | |
glDetachShader(program, fragShader) | |
glDeleteShader(fragShader) | |
} | |
return true | |
} | |
func compileShader(_ shader: inout GLuint, type: GLenum, file: String) -> Bool { | |
var status: GLint = 0 | |
var source: UnsafePointer<Int8> | |
do { | |
source = try NSString(contentsOfFile: file, encoding: String.Encoding.utf8.rawValue).utf8String! | |
} catch { | |
print("Failed to load vertex shader") | |
return false | |
} | |
var castSource: UnsafePointer<GLchar>? = UnsafePointer<GLchar>(source) | |
shader = glCreateShader(type) | |
glShaderSource(shader, 1, &castSource, nil) | |
glCompileShader(shader) | |
//#if defined(DEBUG) | |
// var logLength: GLint = 0 | |
// glGetShaderiv(shader, GLenum(GL_INFO_LOG_LENGTH), &logLength) | |
// if logLength > 0 { | |
// var log = UnsafeMutablePointer<GLchar>(malloc(Int(logLength))) | |
// glGetShaderInfoLog(shader, logLength, &logLength, log) | |
// NSLog("Shader compile log: \n%s", log) | |
// free(log) | |
// } | |
//#endif | |
glGetShaderiv(shader, GLenum(GL_COMPILE_STATUS), &status) | |
if status == 0 { | |
glDeleteShader(shader) | |
return false | |
} | |
return true | |
} | |
func linkProgram(_ prog: GLuint) -> Bool { | |
var status: GLint = 0 | |
glLinkProgram(prog) | |
//#if defined(DEBUG) | |
// var logLength: GLint = 0 | |
// glGetShaderiv(shader, GLenum(GL_INFO_LOG_LENGTH), &logLength) | |
// if logLength > 0 { | |
// var log = UnsafeMutablePointer<GLchar>(malloc(Int(logLength))) | |
// glGetShaderInfoLog(shader, logLength, &logLength, log) | |
// NSLog("Shader compile log: \n%s", log) | |
// free(log) | |
// } | |
//#endif | |
glGetProgramiv(prog, GLenum(GL_LINK_STATUS), &status) | |
if status == 0 { | |
return false | |
} | |
return true | |
} | |
func validateProgram(prog: GLuint) -> Bool { | |
var logLength: GLsizei = 0 | |
var status: GLint = 0 | |
glValidateProgram(prog) | |
glGetProgramiv(prog, GLenum(GL_INFO_LOG_LENGTH), &logLength) | |
if logLength > 0 { | |
var log: [GLchar] = [GLchar](repeating: 0, count: Int(logLength)) | |
glGetProgramInfoLog(prog, logLength, &logLength, &log) | |
print("Program validate log: \n\(log)") | |
} | |
glGetProgramiv(prog, GLenum(GL_VALIDATE_STATUS), &status) | |
var returnVal = true | |
if status == 0 { | |
returnVal = false | |
} | |
return returnVal | |
} | |
// MARK: - touch handling | |
@IBAction func handlePan(_ recognizer:UIPanGestureRecognizer) { | |
if (recognizer.state == .cancelled || recognizer.state == .ended) { | |
mouse = GLKVector2Make(0.0, 0.0) | |
return | |
} | |
let location = recognizer.location(in: self.view) | |
let scale = UIScreen.main.nativeScale | |
mouse = GLKVector2Make(Float(location.x*scale), Float((self.view.bounds.size.height - location.y)*scale)) | |
}} | |
var gCubeVertexData: [GLfloat] = [ | |
// positionX, positionY, positionZ | |
-1.0, -1.0, | |
1.0, -1.0, | |
-1.0, 1.0, | |
-1.0, 1.0, | |
1.0, -1.0, | |
1.0, 1.0, | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment