Skip to content

Instantly share code, notes, and snippets.

@traysr
Last active February 22, 2021 14:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save traysr/352a7df6f0322156c26b07ac6d74cf88 to your computer and use it in GitHub Desktop.
Save traysr/352a7df6f0322156c26b07ac6d74cf88 to your computer and use it in GitHub Desktop.
iOS Setup for bookofshaders.com
#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);
}
//
// 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;
}
//
// 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