port some examples into cookbook-rn
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "glrn-ex",
|
||||
"description": "An empty new project",
|
||||
"slug": "glrn-ex",
|
||||
"sdkVersion": "11.0.3",
|
||||
"name": "glrn-cookbook",
|
||||
"description": "GL React Native Cookbook",
|
||||
"slug": "glrn-cookbook",
|
||||
"sdkVersion": "12.0.0",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"primaryColor": "#cccccc",
|
||||
|
||||
@ -1,32 +1,4 @@
|
||||
import "exponent";
|
||||
import Exponent from "exponent";
|
||||
import React from "react";
|
||||
import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
} from "react-native";
|
||||
import HelloGL from "./HelloGL";
|
||||
import HelloTexture from "./HelloTexture";
|
||||
|
||||
class App extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<HelloGL />
|
||||
<HelloTexture />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: "#fff",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexDirection: "column",
|
||||
},
|
||||
});
|
||||
|
||||
import App from "./src";
|
||||
Exponent.registerRootComponent(App);
|
||||
|
||||
22
cookbook-rn/package.json
Executable file → Normal file
@ -1,15 +1,23 @@
|
||||
{
|
||||
"name": "glrn-ex",
|
||||
"name": "glrn-cookbook",
|
||||
"version": "0.0.0",
|
||||
"description": "Hello Exponent!",
|
||||
"author": null,
|
||||
"description": "GL React Native cookbook",
|
||||
"author": "Gaëtan Renaudeau",
|
||||
"private": true,
|
||||
"main": "main.js",
|
||||
"dependencies": {
|
||||
"exponent": "^11.0.3-rc.1",
|
||||
"gl-react": "file:../packages/gl-react",
|
||||
"gl-react-native": "file:../packages/gl-react-native",
|
||||
"@exponent/ex-navigation": "^2.3.0",
|
||||
"exponent": "^12.0.5",
|
||||
"gl-react": "^3.0.0-alpha1",
|
||||
"gl-react-native": "^3.0.0-alpha1",
|
||||
"glsl-transitions": "^2016.12.26",
|
||||
"ndarray": "^1.0.18",
|
||||
"raf": "^3.3.0",
|
||||
"react": "~15.3.2",
|
||||
"react-native": "github:exponentjs/react-native#sdk-11.0.2"
|
||||
"react-motion": "^0.4.7",
|
||||
"react-native": "github:exponentjs/react-native#sdk-12.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"generate-examples": "cd src/examples; ./gen.sh 1> index.js"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
cookbook-rn/src/0BJobQo.jpg
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
cookbook-rn/src/0PkQEk1.jpg
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
cookbook-rn/src/0bUSEBX.jpg
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
cookbook-rn/src/2VP5osy.jpg
Normal file
|
After Width: | Height: | Size: 242 KiB |
|
Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 155 KiB |
BIN
cookbook-rn/src/CKlmtPs.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
cookbook-rn/src/G2Whuq3.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
cookbook-rn/src/GQo1KWq.jpg
Normal file
|
After Width: | Height: | Size: 296 KiB |
76
cookbook-rn/src/HOC/respondToTouchPosition.js
Normal file
@ -0,0 +1,76 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { PanResponder, View } from "react-native";
|
||||
import hoistNonReactStatics from "hoist-non-react-statics";
|
||||
|
||||
type Pos = { x: number, y: number };
|
||||
type State = { touching: boolean, touchPosition: Pos };
|
||||
|
||||
export default (Comp: ReactClass<*>, {
|
||||
initialPosition = { x: 0.5, y: 0.5 }
|
||||
}: { initialPosition: Pos } = {}) => {
|
||||
class TouchPositionResponding extends Component {
|
||||
state: State = {
|
||||
touching: false,
|
||||
touchPosition: initialPosition,
|
||||
};
|
||||
initialContainerPos: [number, number];
|
||||
initialDragPos: [number, number];
|
||||
size: [number, number];
|
||||
panResponder = PanResponder.create({
|
||||
onStartShouldSetPanResponder: () => true,
|
||||
onStartShouldSetPanResponderCapture: () => true,
|
||||
onMoveShouldSetPanResponder: () => true,
|
||||
onMoveShouldSetPanResponderCapture: () => true,
|
||||
onPanResponderGrant: (evt) => {
|
||||
const { pageX, pageY } = evt.nativeEvent;
|
||||
this.initialDragPos = [ pageX, pageY ];
|
||||
this.refs.root.measure((x, y, w, h, initialPageX, initialPageY) => {
|
||||
this.initialContainerPos = [ initialPageX, initialPageY ];
|
||||
this.size = [ w, h ];
|
||||
this.setState({
|
||||
touching: true,
|
||||
touchPosition: {
|
||||
x: (pageX - initialPageX) / w,
|
||||
y: 1 - (pageY - initialPageY) / h,
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
onPanResponderMove: (evt, gestureState) => {
|
||||
const [ pageX, pageY ] = this.initialDragPos;
|
||||
const [ initialPageX, initialPageY ] = this.initialContainerPos;
|
||||
const { dx, dy } = gestureState;
|
||||
const [ w, h ] = this.size;
|
||||
this.setState({
|
||||
touchPosition: {
|
||||
x: (pageX + dx - initialPageX) / w,
|
||||
y: 1 - (pageY + dy - initialPageY) / h,
|
||||
}
|
||||
});
|
||||
},
|
||||
onPanResponderTerminationRequest: () => true,
|
||||
onPanResponderRelease: () => this._onEnd(),
|
||||
onPanResponderTerminate: () => this._onEnd(),
|
||||
onShouldBlockNativeResponder: () => true,
|
||||
});
|
||||
_onEnd = () => {
|
||||
if (this.state.touching) {
|
||||
this.setState({
|
||||
touching: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
render() {
|
||||
return (
|
||||
<View ref="root" {...this.panResponder.panHandlers}>
|
||||
<Comp {...this.props} {...this.state} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
hoistNonReactStatics(TouchPositionResponding, Comp);
|
||||
|
||||
return TouchPositionResponding;
|
||||
};
|
||||
50
cookbook-rn/src/HOC/timeLoop.js
Normal file
@ -0,0 +1,50 @@
|
||||
//@flow
|
||||
import React, { PureComponent } from "react";
|
||||
import raf from "raf";
|
||||
import hoistNonReactStatics from "hoist-non-react-statics";
|
||||
|
||||
// NB this is only an utility for the examples
|
||||
export default (
|
||||
C: ReactClass<*>,
|
||||
{ refreshRate = 60 }: { refreshRate?: number } = {}
|
||||
): ReactClass<*> => {
|
||||
class TL extends PureComponent {
|
||||
static displayName = `timeLoop(${C.displayName||C.name||""})`;
|
||||
state: { time: number };
|
||||
state = {
|
||||
time: 0,
|
||||
tick: 0,
|
||||
};
|
||||
_r: any;
|
||||
componentDidMount() {
|
||||
let startTime: number, lastTime: number;
|
||||
let interval = 1000 / refreshRate;
|
||||
lastTime = -interval;
|
||||
const loop = (t: number) => {
|
||||
this._r = raf(loop);
|
||||
if (!startTime) startTime = t;
|
||||
if (t - lastTime > interval) {
|
||||
lastTime = t;
|
||||
this.setState({
|
||||
time: t - startTime,
|
||||
tick: this.state.tick + 1,
|
||||
});
|
||||
}
|
||||
};
|
||||
this._r = raf(loop);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
raf.cancel(this._r);
|
||||
}
|
||||
render() {
|
||||
return <C
|
||||
{...this.props}
|
||||
{...this.state}
|
||||
/>;
|
||||
}
|
||||
};
|
||||
|
||||
hoistNonReactStatics(TL, C);
|
||||
|
||||
return TL;
|
||||
}
|
||||
99
cookbook-rn/src/Home.js
Normal file
@ -0,0 +1,99 @@
|
||||
|
||||
import React from "react";
|
||||
import {
|
||||
Image,
|
||||
StyleSheet,
|
||||
Text,
|
||||
ScrollView,
|
||||
View,
|
||||
} from "react-native";
|
||||
import ListItem from "./ListItem";
|
||||
import * as examples from "./examples";
|
||||
import Router from "./Router";
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: "#fff",
|
||||
flexDirection: "column",
|
||||
},
|
||||
list: {
|
||||
flex: 1,
|
||||
},
|
||||
subHeader: {
|
||||
padding: 10,
|
||||
backgroundColor: "#f9f9f9",
|
||||
},
|
||||
subHeaderText: {
|
||||
color: "#333",
|
||||
fontSize: 12,
|
||||
fontStyle: "italic",
|
||||
},
|
||||
title: {
|
||||
flex: 1,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
titleImage: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
marginRight: 12,
|
||||
},
|
||||
titleText: {
|
||||
fontWeight: "bold",
|
||||
color: "#fff",
|
||||
fontSize: 18,
|
||||
},
|
||||
});
|
||||
|
||||
export default class Home extends React.Component {
|
||||
static route = {
|
||||
navigationBar: {
|
||||
renderTitle: () =>
|
||||
<View style={styles.title}>
|
||||
<Text style={styles.titleText}>gl-react-native</Text>
|
||||
</View>
|
||||
},
|
||||
};
|
||||
props: {
|
||||
navigator: *,
|
||||
};
|
||||
render() {
|
||||
const {navigator} = this.props;
|
||||
return (
|
||||
<ScrollView style={styles.container} bounces={false}>
|
||||
<View style={styles.subHeader}>
|
||||
<Text style={styles.subHeaderText}>
|
||||
a React Native library to write and compose WebGL shaders
|
||||
</Text>
|
||||
<View style={{ alignItems: "center", padding: 20 /* TMP it will be the home demo */ }}>
|
||||
<Image
|
||||
source={require("./logo.png")}
|
||||
style={{ width: 200, height: 200 }}
|
||||
/>
|
||||
</View>
|
||||
<Text style={styles.subHeaderText}>
|
||||
Here is a collection of gl-react-native examples:
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.list}>
|
||||
{Object.keys(examples).map(ex => {
|
||||
const { title, description, Example } = examples[ex];
|
||||
return <ListItem
|
||||
key={ex}
|
||||
title={title}
|
||||
description={description||""}
|
||||
disabled={!Example}
|
||||
onPress={
|
||||
Example
|
||||
? () => navigator.push(Router.getRoute(ex))
|
||||
: null
|
||||
}
|
||||
/>;
|
||||
})}
|
||||
</View>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
}
|
||||
BIN
cookbook-rn/src/IvpoR40.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
47
cookbook-rn/src/ListItem.js
Normal file
@ -0,0 +1,47 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
} from "react-native";
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: "#fff",
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderBottomColor: "rgba(0, 0, 0, .1)",
|
||||
paddingVertical: 10,
|
||||
paddingHorizontal: 14,
|
||||
},
|
||||
title: {
|
||||
fontSize: 16,
|
||||
fontWeight: "bold",
|
||||
color: "#222",
|
||||
margin: 2,
|
||||
},
|
||||
titleDisabled: {
|
||||
color: "#aaa",
|
||||
},
|
||||
description: {
|
||||
fontSize: 12,
|
||||
color: "#888",
|
||||
margin: 2,
|
||||
},
|
||||
});
|
||||
|
||||
type Props = {
|
||||
title: string,
|
||||
description: string,
|
||||
onPress: Function,
|
||||
disabled?: boolean,
|
||||
};
|
||||
|
||||
export default function ListItem({ title, description, onPress, disabled }: Props) {
|
||||
return (
|
||||
<TouchableOpacity style={styles.container} onPress={onPress} disabled={disabled}>
|
||||
<Text style={[styles.title, disabled ? styles.titleDisabled : null ]}>{title}</Text>
|
||||
<Text style={styles.description}>{description}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
BIN
cookbook-rn/src/MnOB9Le.jpg
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
cookbook-rn/src/NjbLHx2.jpg
Normal file
|
After Width: | Height: | Size: 686 KiB |
BIN
cookbook-rn/src/Otbz312.jpg
Normal file
|
After Width: | Height: | Size: 53 KiB |
16
cookbook-rn/src/Router.js
Normal file
@ -0,0 +1,16 @@
|
||||
//@flow
|
||||
import {
|
||||
createRouter,
|
||||
} from "@exponent/ex-navigation";
|
||||
import * as examples from "./examples";
|
||||
import Home from "./Home";
|
||||
import makeExample from "./makeExample";
|
||||
export default createRouter(() => {
|
||||
const routes = {
|
||||
home: () => Home,
|
||||
};
|
||||
Object.keys(examples).map(k => {
|
||||
routes[k] = () => makeExample(examples[k], k);
|
||||
});
|
||||
return routes;
|
||||
});
|
||||
BIN
cookbook-rn/src/SzbbUvX.jpg
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
cookbook-rn/src/YqsZKgc.jpg
Normal file
|
After Width: | Height: | Size: 81 KiB |
165
cookbook-rn/src/examples/_TODO_blurimgtitle/index.js
Normal file
@ -0,0 +1,165 @@
|
||||
//@flow
|
||||
import React, { PureComponent, Component, PropTypes } from "react";
|
||||
import { Shaders, Node, GLSL, Bus, LinearCopy } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import JSON2D from "react-json2d";
|
||||
import {Blur1D} from "../blurxy";
|
||||
import {Blur} from "../blurmulti";
|
||||
import {BlurV} from "../blurmap";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
ImageTitle: {
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform sampler2D img, imgBlurred, imgTone, title, blurMap;
|
||||
uniform float colorThreshold;
|
||||
float monochrome (vec3 c) {
|
||||
return 0.2125 * c.r + 0.7154 * c.g + 0.0721 * c.b;
|
||||
}
|
||||
void main() {
|
||||
float blurFactor = texture2D(blurMap, uv).r;
|
||||
vec4 bgColor = mix(
|
||||
texture2D(img, uv),
|
||||
texture2D(imgBlurred, uv),
|
||||
step(0.01, blurFactor)
|
||||
);
|
||||
vec4 textColor = vec4(vec3(
|
||||
step(monochrome(texture2D(imgTone, uv).rgb), colorThreshold)
|
||||
), 1.0);
|
||||
float isText = 1.0 - texture2D(title, uv).r;
|
||||
gl_FragColor = mix(bgColor, textColor, isText);
|
||||
}`
|
||||
},
|
||||
TitleBlurMap: {
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform sampler2D t;
|
||||
uniform float threshold;
|
||||
void main() {
|
||||
gl_FragColor = vec4(
|
||||
vec3(smoothstep(1.0, threshold, texture2D(t, uv).r)),
|
||||
1.0);
|
||||
}`
|
||||
},
|
||||
});
|
||||
|
||||
const AveragePixels = ({ children, quality }) =>
|
||||
<Blur1D
|
||||
width={1}
|
||||
height={1}
|
||||
resolution={[ 1, 1 ]}
|
||||
direction={[ 0, 0.1 ]}>
|
||||
<Blur1D
|
||||
width={1}
|
||||
height={quality}
|
||||
resolution={[ 1, quality ]}
|
||||
direction={[ 0.1, 0 ]}>
|
||||
{children}
|
||||
</Blur1D>
|
||||
</Blur1D>;
|
||||
|
||||
const TitleBlurMap = ({ children: title, threshold }) =>
|
||||
<Node
|
||||
shader={shaders.TitleBlurMap}
|
||||
uniforms={{
|
||||
threshold,
|
||||
t:
|
||||
<Blur factor={4} passes={4} width={200} height={200}>
|
||||
{title}
|
||||
</Blur>
|
||||
}}
|
||||
width={64}
|
||||
height={64}
|
||||
/>;
|
||||
|
||||
class Title extends PureComponent {
|
||||
render () {
|
||||
const { children, width, height } = this.props;
|
||||
return <LinearCopy><JSON2D width={width} height={height}>{{
|
||||
size: [ width, height ],
|
||||
background: "#fff",
|
||||
draws: [
|
||||
{
|
||||
"font": "bold 78px Didot,Georgia,serif",
|
||||
"fillStyle": "#000",
|
||||
"textBaseline": "top",
|
||||
"textAlign": "center"
|
||||
},
|
||||
[ "fillText", children, width/2, 10, 84 ],
|
||||
]
|
||||
}}</JSON2D></LinearCopy>;
|
||||
}
|
||||
}
|
||||
|
||||
class ImageTitle extends Component {
|
||||
static contextTypes = {
|
||||
width: PropTypes.number.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
};
|
||||
render() {
|
||||
const { children: img, text, colorThreshold } = this.props;
|
||||
const { width, height } = this.context;
|
||||
return (
|
||||
<Node
|
||||
shader={shaders.ImageTitle}
|
||||
uniforms={{
|
||||
colorThreshold,
|
||||
img,
|
||||
imgBlurred:() => this.refs.imgBlurred,
|
||||
title:() => this.refs.title,
|
||||
imgTone:() => this.refs.imgTone,
|
||||
blurMap:() => this.refs.blurMap,
|
||||
}}>
|
||||
|
||||
<Bus ref="title">
|
||||
<Title width={width} height={height}>
|
||||
{text}
|
||||
</Title>
|
||||
</Bus>
|
||||
|
||||
<Bus ref="blurMap">
|
||||
<TitleBlurMap threshold={0.7}>
|
||||
{() => this.refs.title}
|
||||
</TitleBlurMap>
|
||||
</Bus>
|
||||
|
||||
<Bus ref="imgTone">
|
||||
<AveragePixels quality={8}>
|
||||
{img}
|
||||
</AveragePixels>
|
||||
</Bus>
|
||||
|
||||
<Bus ref="imgBlurred">
|
||||
<BlurV
|
||||
map={() => this.refs.blurMap}
|
||||
factor={4}
|
||||
passes={4}>
|
||||
{img}
|
||||
</BlurV>
|
||||
</Bus>
|
||||
|
||||
</Node>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default class Example extends Component {
|
||||
render() {
|
||||
const { title, colorThreshold, image } = this.props;
|
||||
return (
|
||||
<Surface width={450} height={300}>
|
||||
<ImageTitle text={title} colorThreshold={colorThreshold}>
|
||||
{image}
|
||||
</ImageTitle>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
title: "Hello\nSan Francisco\n☻",
|
||||
colorThreshold: 0.6,
|
||||
image: require("./sf-6.jpg"),
|
||||
};
|
||||
}
|
||||
36
cookbook-rn/src/examples/_TODO_blurimgtitle/meta.js
Normal file
@ -0,0 +1,36 @@
|
||||
import ImagesPicker from "../../toolbox/ImagesPicker";
|
||||
import makeTextArea from "../../toolbox/makeTextArea";
|
||||
import makeFloatSlider from "../../toolbox/makeFloatSlider";
|
||||
|
||||
export const title = "Dynamic Blur Image Title";
|
||||
|
||||
export const toolbox = [
|
||||
{ prop: "title",
|
||||
title: "Title",
|
||||
Editor: makeTextArea({
|
||||
height: 140,
|
||||
padding: 6,
|
||||
fontFamily: "Didot,Georgia,serif",
|
||||
fontSize: "36px",
|
||||
lineHeight: "42px",
|
||||
fontWeight: "bold",
|
||||
textAlign: "center",
|
||||
}) },
|
||||
{ prop: "colorThreshold",
|
||||
title: "Color Threshold",
|
||||
Editor: makeFloatSlider(0, 1, 0.01) }, // FIXME black <-> white
|
||||
{ prop: "image",
|
||||
title: "Image",
|
||||
Editor: ImagesPicker,
|
||||
style: { width: 400 },
|
||||
imageStyle: { maxWidth: 56, maxHeight: 56, marginBottom: 16, },
|
||||
images: [
|
||||
require("./sf-1.jpg"),
|
||||
require("./sf-2.jpg"),
|
||||
require("./sf-3.jpg"),
|
||||
require("./sf-4.jpg"),
|
||||
require("./sf-5.jpg"),
|
||||
require("./sf-6.jpg"),
|
||||
require("./sf-7.jpg"),
|
||||
] },
|
||||
];
|
||||
BIN
cookbook-rn/src/examples/_TODO_blurimgtitle/sf-1.jpg
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
cookbook-rn/src/examples/_TODO_blurimgtitle/sf-2.jpg
Normal file
|
After Width: | Height: | Size: 259 KiB |
BIN
cookbook-rn/src/examples/_TODO_blurimgtitle/sf-3.jpg
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
cookbook-rn/src/examples/_TODO_blurimgtitle/sf-4.jpg
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
cookbook-rn/src/examples/_TODO_blurimgtitle/sf-5.jpg
Normal file
|
After Width: | Height: | Size: 220 KiB |
BIN
cookbook-rn/src/examples/_TODO_blurimgtitle/sf-6.jpg
Normal file
|
After Width: | Height: | Size: 401 KiB |
BIN
cookbook-rn/src/examples/_TODO_blurimgtitle/sf-7.jpg
Normal file
|
After Width: | Height: | Size: 168 KiB |
54
cookbook-rn/src/examples/animated/index.js
Normal file
@ -0,0 +1,54 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { Animated, PanResponder, View } from "react-native";
|
||||
import { Shaders, Node, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import respondToTouchPosition from "../../HOC/respondToTouchPosition";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
cursor: { frag: GLSL`
|
||||
precision lowp float; varying vec2 uv; uniform vec2 style;
|
||||
void main() {
|
||||
float dist = pow(1.0 - distance(style, uv), 8.0);
|
||||
gl_FragColor = vec4(smoothstep(2.0, 0.2, distance(style, uv)) * vec3(
|
||||
1.0 * dist + pow(1.0 - distance(style.y, uv.y), 16.0),
|
||||
0.5 * dist + pow(1.0 - distance(style.y, uv.y), 32.0),
|
||||
0.2 * dist + pow(1.0 - distance(style.x, uv.x), 32.0)), 1.0);
|
||||
}` }
|
||||
});
|
||||
|
||||
class Cursor extends Component {
|
||||
render() {
|
||||
const { style: { x, y } } = this.props;
|
||||
return <Node shader={shaders.cursor} uniforms={{ style: [ x, y ] }} />;
|
||||
}
|
||||
}
|
||||
|
||||
// using "style" is a hack. see https://github.com/animatedjs/animated/issues/45
|
||||
const AnimatedCursor = Animated.createAnimatedComponent(Cursor);
|
||||
|
||||
export default respondToTouchPosition(class Example extends Component {
|
||||
props: {
|
||||
touchPosition: {
|
||||
x: number,
|
||||
y: number,
|
||||
},
|
||||
};
|
||||
state = {
|
||||
style: new Animated.ValueXY(this.props.touchPosition)
|
||||
};
|
||||
componentWillReceiveProps ({ touchPosition }) {
|
||||
if (this.props.touchPosition !== touchPosition) {
|
||||
Animated.spring(this.state.style, {
|
||||
toValue: touchPosition,
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Surface width={300} height={300}>
|
||||
<AnimatedCursor {...this.state} />
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
});
|
||||
1
cookbook-rn/src/examples/animated/meta.js
Normal file
@ -0,0 +1 @@
|
||||
export const title = "Cursor spring effect with animated";
|
||||
67
cookbook-rn/src/examples/blurmap/index.js
Normal file
@ -0,0 +1,67 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { Shaders, Node, GLSL, connectSize } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
blurV1D: {
|
||||
frag: GLSL`precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform sampler2D t, map;
|
||||
uniform vec2 direction, resolution;
|
||||
vec4 blur9(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
|
||||
vec4 color = vec4(0.0);
|
||||
vec2 off1 = vec2(1.3846153846) * direction;
|
||||
vec2 off2 = vec2(3.2307692308) * direction;
|
||||
color += texture2D(image, uv) * 0.2270270270;
|
||||
color += texture2D(image, uv + (off1 / resolution)) * 0.3162162162;
|
||||
color += texture2D(image, uv - (off1 / resolution)) * 0.3162162162;
|
||||
color += texture2D(image, uv + (off2 / resolution)) * 0.0702702703;
|
||||
color += texture2D(image, uv - (off2 / resolution)) * 0.0702702703;
|
||||
return color;
|
||||
}
|
||||
void main() {
|
||||
gl_FragColor = blur9(t, uv, resolution, direction * texture2D(map, uv).rg);
|
||||
}` }
|
||||
});
|
||||
|
||||
// Same concept than Blur1D except it takes one more prop:
|
||||
// a map texture that tells the blur intensity for a given position.
|
||||
export const BlurV1D =
|
||||
connectSize(({ children: t, direction, map, width, height }) =>
|
||||
<Node
|
||||
shader={shaders.blurV1D}
|
||||
uniforms={{ t, map, resolution: [ width, height ], direction }}
|
||||
/>);
|
||||
|
||||
// And its N-pass version
|
||||
import {directionForPass} from "../blurmulti";
|
||||
export const BlurV =
|
||||
connectSize(({ children, factor, map, passes }) => {
|
||||
const rec = pass =>
|
||||
pass <= 0
|
||||
? children
|
||||
: <BlurV1D map={map} direction={directionForPass(pass, factor, passes)}>
|
||||
{rec(pass-1)}
|
||||
</BlurV1D>;
|
||||
return rec(passes);
|
||||
});
|
||||
|
||||
export default class Example extends Component {
|
||||
render() {
|
||||
const { factor, passes, map } = this.props;
|
||||
return (
|
||||
<Surface width={600} height={284}>
|
||||
<BlurV map={map} passes={passes} factor={factor}>
|
||||
{require("../../NjbLHx2.jpg")}
|
||||
</BlurV>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
static defaultProps = {
|
||||
factor: 2,
|
||||
passes: 4,
|
||||
map: StaticBlurMap.images[0],
|
||||
};
|
||||
}
|
||||
import StaticBlurMap from "../../toolbox/StaticBlurMap";
|
||||
14
cookbook-rn/src/examples/blurmap/meta.js
Normal file
@ -0,0 +1,14 @@
|
||||
import StaticBlurMap from "../../toolbox/StaticBlurMap";
|
||||
import makeFloatSlider from "../../toolbox/makeFloatSlider";
|
||||
export const title = "Blur with intensity map & multi-pass";
|
||||
export const toolbox = [
|
||||
{ prop: "factor",
|
||||
title: "Blur",
|
||||
Editor: makeFloatSlider(0, 8, 0.2) },
|
||||
{ prop: "passes",
|
||||
title: value => `Blur Passes (${value})`,
|
||||
Editor: makeFloatSlider(1, 8, 1) },
|
||||
{ prop: "map",
|
||||
title: "Blur Texture Map",
|
||||
Editor: StaticBlurMap },
|
||||
];
|
||||
46
cookbook-rn/src/examples/blurmapdyn/index.js
Normal file
@ -0,0 +1,46 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { Shaders, Node, Bus, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import {BlurV} from "../blurmap";
|
||||
import timeLoop from "../../HOC/timeLoop";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
ConicalGradiant: {
|
||||
frag: GLSL`precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform float phase;
|
||||
const float PI = 3.14159;
|
||||
void main () {
|
||||
gl_FragColor = vec4(vec3(
|
||||
mod(phase + atan(uv.x-0.5, uv.y-0.5)/(2.0*PI), 1.0)
|
||||
), 1.0);
|
||||
}` }
|
||||
});
|
||||
|
||||
const ConicalGradiantLoop = timeLoop(({ time }) =>
|
||||
<Node
|
||||
shader={shaders.ConicalGradiant}
|
||||
uniforms={{ phase: time/3000 }}
|
||||
/>);
|
||||
|
||||
export default class Example extends Component {
|
||||
render() {
|
||||
const { factor, passes } = this.props;
|
||||
// <ConicalGradiant/> also needs to be computed once.
|
||||
return (
|
||||
<Surface width={600} height={284}>
|
||||
<Bus ref="blurMapBus">
|
||||
<ConicalGradiantLoop />
|
||||
</Bus>
|
||||
<BlurV map={() => this.refs.blurMapBus} passes={passes} factor={factor}>
|
||||
{require("../../NjbLHx2.jpg")}
|
||||
</BlurV>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
static defaultProps = {
|
||||
factor: 6,
|
||||
passes: 4,
|
||||
};
|
||||
}
|
||||
11
cookbook-rn/src/examples/blurmapdyn/meta.js
Normal file
@ -0,0 +1,11 @@
|
||||
import makeFloatSlider from "../../toolbox/makeFloatSlider";
|
||||
export const title = "Blur with dynamic shader mapping";
|
||||
export const desc = "Any arbitrary shader can be used as a blur map!";
|
||||
export const toolbox = [
|
||||
{ prop: "factor",
|
||||
title: "Blur",
|
||||
Editor: makeFloatSlider(0, 8, 0.2) },
|
||||
{ prop: "passes",
|
||||
title: value => `Blur Passes (${value})`,
|
||||
Editor: makeFloatSlider(1, 8, 1) },
|
||||
];
|
||||
61
cookbook-rn/src/examples/blurmapmouse/index.js
Normal file
@ -0,0 +1,61 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { Shaders, Node, Bus, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import {BlurV} from "../blurmap";
|
||||
import respondToTouchPosition from "../../HOC/respondToTouchPosition";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
Offset: {
|
||||
frag: GLSL`precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform sampler2D t;
|
||||
uniform vec2 offset;
|
||||
void main () {
|
||||
gl_FragColor = texture2D(t, uv + offset);
|
||||
}`
|
||||
}
|
||||
});
|
||||
|
||||
const Offset = ({ t, offset }) =>
|
||||
<Node shader={shaders.Offset} uniforms={{ t, offset }} />;
|
||||
|
||||
const Example = respondToTouchPosition(class Example extends Component {
|
||||
render() {
|
||||
const { map, touching, touchPosition } = this.props;
|
||||
// Sharing computation of a GL Node.
|
||||
// <Offset /> should not be passed straight to BlurV's map because
|
||||
// it would duplicates it in the tree ([passes] times)
|
||||
// Instead, we need to express a graph and share the
|
||||
// computation with a Bus ref.
|
||||
// We pass to BlurV's map prop a function that resolve that ref.
|
||||
return (
|
||||
<Surface width={300} height={142}>
|
||||
<Bus ref="blurMapBus">
|
||||
<Offset
|
||||
offset={
|
||||
touching
|
||||
? [
|
||||
touchPosition.x - 0.5,
|
||||
touchPosition.y - 0.5
|
||||
]
|
||||
: [ 0, 0 ]
|
||||
}
|
||||
t={map}
|
||||
/>
|
||||
</Bus>
|
||||
<BlurV map={() => this.refs.blurMapBus} passes={6} factor={6}>
|
||||
{require("../../NjbLHx2.jpg")}
|
||||
</BlurV>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Example.defaultProps = {
|
||||
map: StaticBlurMap.images[0],
|
||||
};
|
||||
|
||||
export default Example;
|
||||
|
||||
import StaticBlurMap from "../../toolbox/StaticBlurMap";
|
||||
8
cookbook-rn/src/examples/blurmapmouse/meta.js
Normal file
@ -0,0 +1,8 @@
|
||||
import StaticBlurMap from "../../toolbox/StaticBlurMap";
|
||||
export const title = "Blur map and Mouse position";
|
||||
export const description = "Dynamically change Blur Map with touch move";
|
||||
export const toolbox = [
|
||||
{ prop: "map",
|
||||
title: "Blur Texture Map",
|
||||
Editor: StaticBlurMap },
|
||||
];
|
||||
45
cookbook-rn/src/examples/blurmulti/index.js
Normal file
@ -0,0 +1,45 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { connectSize } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import { Blur1D } from "../blurxy";
|
||||
|
||||
// empirical strategy to chose a 2d vector for a blur pass
|
||||
const NORM = Math.sqrt(2)/2;
|
||||
export const directionForPass = (p: number, factor: number, total: number) => {
|
||||
const f = factor * 2 * Math.ceil(p / 2) / total;
|
||||
switch ((p-1) % 4) { // alternate horizontal, vertical and 2 diagonals
|
||||
case 0: return [f,0];
|
||||
case 1: return [0,f];
|
||||
case 2: return [f*NORM,f*NORM];
|
||||
default: return [f*NORM,-f*NORM];
|
||||
}
|
||||
}
|
||||
|
||||
// recursively apply Blur1D to make a multi pass Blur component
|
||||
export const Blur = connectSize(({ children, factor, passes }) => {
|
||||
const rec = pass =>
|
||||
pass <= 0
|
||||
? children
|
||||
: <Blur1D direction={directionForPass(pass, factor, passes)}>
|
||||
{rec(pass-1)}
|
||||
</Blur1D>;
|
||||
return rec(passes);
|
||||
});
|
||||
|
||||
export default class Example extends Component {
|
||||
render() {
|
||||
const { factor, passes } = this.props;
|
||||
return (
|
||||
<Surface width={400} height={300}>
|
||||
<Blur passes={passes} factor={factor}>
|
||||
{require("../../iPKTONG.jpg")}
|
||||
</Blur>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
static defaultProps = {
|
||||
factor: 2,
|
||||
passes: 4,
|
||||
};
|
||||
}
|
||||
11
cookbook-rn/src/examples/blurmulti/meta.js
Normal file
@ -0,0 +1,11 @@
|
||||
import makeFloatSlider from "../../toolbox/makeFloatSlider";
|
||||
export const title = "multi-pass Blur";
|
||||
|
||||
export const toolbox = [
|
||||
{ prop: "factor",
|
||||
title: "Blur",
|
||||
Editor: makeFloatSlider(0, 8, 0.2) },
|
||||
{ prop: "passes",
|
||||
title: passes => `Blur Passes (${passes})`,
|
||||
Editor: makeFloatSlider(0, 8, 1) },
|
||||
];
|
||||
61
cookbook-rn/src/examples/blurxy/index.js
Normal file
@ -0,0 +1,61 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import {Shaders, Node, GLSL, connectSize} from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
blur1D: { // blur9: from https://github.com/Jam3/glsl-fast-gaussian-blur
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform sampler2D t;
|
||||
uniform vec2 direction, resolution;
|
||||
vec4 blur9(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
|
||||
vec4 color = vec4(0.0);
|
||||
vec2 off1 = vec2(1.3846153846) * direction;
|
||||
vec2 off2 = vec2(3.2307692308) * direction;
|
||||
color += texture2D(image, uv) * 0.2270270270;
|
||||
color += texture2D(image, uv + (off1 / resolution)) * 0.3162162162;
|
||||
color += texture2D(image, uv - (off1 / resolution)) * 0.3162162162;
|
||||
color += texture2D(image, uv + (off2 / resolution)) * 0.0702702703;
|
||||
color += texture2D(image, uv - (off2 / resolution)) * 0.0702702703;
|
||||
return color;
|
||||
}
|
||||
void main() {
|
||||
gl_FragColor = blur9(t, uv, resolution, direction);
|
||||
}` }
|
||||
});
|
||||
|
||||
// This implements a blur on a single direction (x or y axis for instance)
|
||||
// connectSize will inject for us the width/height from context if not provided
|
||||
export const Blur1D =
|
||||
connectSize(({ children: t, direction, width, height }) =>
|
||||
<Node
|
||||
shader={shaders.blur1D}
|
||||
uniforms={{ t, resolution: [ width, height ], direction }}
|
||||
/>);
|
||||
|
||||
// BlurXY is a basic blur that apply Blur1D on Y and then on X
|
||||
export const BlurXY =
|
||||
connectSize(({ factor, children }) =>
|
||||
<Blur1D direction={[ factor, 0 ]}>
|
||||
<Blur1D direction={[ 0, factor ]}>
|
||||
{children}
|
||||
</Blur1D>
|
||||
</Blur1D>);
|
||||
|
||||
export default class Example extends Component {
|
||||
render() {
|
||||
const { factor } = this.props;
|
||||
return (
|
||||
<Surface width={400} height={300}>
|
||||
<BlurXY factor={factor}>
|
||||
{require("../../iPKTONG.jpg")}
|
||||
</BlurXY>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
static defaultProps = {
|
||||
factor: 1,
|
||||
};
|
||||
}
|
||||
8
cookbook-rn/src/examples/blurxy/meta.js
Normal file
@ -0,0 +1,8 @@
|
||||
import makeFloatSlider from "../../toolbox/makeFloatSlider";
|
||||
export const title = "simple Blur (2-passes)";
|
||||
|
||||
export const toolbox = [
|
||||
{ prop: "factor",
|
||||
title: "Blur",
|
||||
Editor: makeFloatSlider(0, 8, 0.2) },
|
||||
];
|
||||
24
cookbook-rn/src/examples/blurxydownscale/index.js
Normal file
@ -0,0 +1,24 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import {LinearCopy} from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import {BlurXY} from "../blurxy";
|
||||
|
||||
export default class Example extends Component {
|
||||
render() {
|
||||
const { factor } = this.props;
|
||||
return (
|
||||
<Surface width={400} height={300}>
|
||||
<LinearCopy>
|
||||
<BlurXY factor={factor} width={100} height={75}>
|
||||
{require("../../iPKTONG.jpg")}
|
||||
</BlurXY>
|
||||
</LinearCopy>
|
||||
</Surface>
|
||||
// we have to wrap this in a <LinearCopy> so it upscales to the Surface size.
|
||||
);
|
||||
}
|
||||
static defaultProps = {
|
||||
factor: 0.5,
|
||||
};
|
||||
}
|
||||
8
cookbook-rn/src/examples/blurxydownscale/meta.js
Normal file
@ -0,0 +1,8 @@
|
||||
import makeFloatSlider from "../../toolbox/makeFloatSlider";
|
||||
export const title = "simple Blur + downscale";
|
||||
|
||||
export const toolbox = [
|
||||
{ prop: "factor",
|
||||
title: "Blur",
|
||||
Editor: makeFloatSlider(0.2, 0.8, 0.02) },
|
||||
];
|
||||
47
cookbook-rn/src/examples/colordisc/index.js
Normal file
@ -0,0 +1,47 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { Shaders, Node, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
const shaders = Shaders.create({
|
||||
ColoredDisc: {
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform vec3 fromColor, toColor;
|
||||
void main() {
|
||||
float d = 2.0 * distance(uv, vec2(0.5));
|
||||
gl_FragColor = mix(
|
||||
vec4(mix(fromColor, toColor, d), 1.0),
|
||||
vec4(0.0),
|
||||
step(1.0, d)
|
||||
);
|
||||
}` }
|
||||
});
|
||||
|
||||
class ColoredDisc extends Component {
|
||||
render() {
|
||||
// fromColor/toColor must be array of 3 numbers because defined as vec3 type.
|
||||
const { fromColor, toColor } = this.props;
|
||||
return (
|
||||
<Node
|
||||
shader={shaders.ColoredDisc}
|
||||
uniforms={{ fromColor, toColor }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default class Example extends Component {
|
||||
render() {
|
||||
const { fromColor, toColor } = this.props;
|
||||
return (
|
||||
<Surface width={300} height={300}>
|
||||
<ColoredDisc fromColor={fromColor} toColor={toColor} />
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
static defaultProps = {
|
||||
fromColor: [ 1, 0, 1 ],
|
||||
toColor: [ 1, 1, 0 ],
|
||||
};
|
||||
}
|
||||
9
cookbook-rn/src/examples/colordisc/meta.js
Normal file
@ -0,0 +1,9 @@
|
||||
import Vec3ColorPicker from "../../toolbox/Vec3ColorPicker";
|
||||
export const toolbox = [
|
||||
{ prop: "fromColor", title: "fromColor", Editor: Vec3ColorPicker },
|
||||
{ prop: "toColor", title: "toColor", Editor: Vec3ColorPicker },
|
||||
];
|
||||
|
||||
export const title = "Colored Disc";
|
||||
|
||||
export const description = "Implement a simple radial gradient with {fromColor, toColor} uniforms.";
|
||||
58
cookbook-rn/src/examples/colorscale/colorScales.js
Normal file
@ -0,0 +1,58 @@
|
||||
const ndarray = require("ndarray");
|
||||
|
||||
module.exports = {
|
||||
heatmap: ndarray(new Float64Array([
|
||||
1, 0, 0,
|
||||
1, 0.6, 0,
|
||||
0.4, 1, 0.4,
|
||||
0.1, 0.7, 1,
|
||||
0, 0, 1,
|
||||
]), [5, 1, 3]).step(-1, 1, 1),
|
||||
|
||||
monochrome: ndarray(new Float64Array([
|
||||
1, 1, 1,
|
||||
0.1, 0.2, 0.3,
|
||||
]), [2, 1, 3]).step(-1, 1, 1),
|
||||
|
||||
opacity: ndarray(new Float64Array([
|
||||
0,
|
||||
1,
|
||||
]), [2, 1, 1]).step(-1, 1, 1), // see gl-texture2d rule: https://github.com/stackgl/gl-texture2d#var-tex--createtexturegl-array
|
||||
|
||||
// from https://github.com/gka/chroma.js/blob/master/src/colors/colorbrewer.coffee
|
||||
OrRd: ndarray(new Float64Array([1.00,0.97,0.93,1.00,0.91,0.78,0.99,0.83,0.62,0.99,0.73,0.52,0.99,0.55,0.35,0.94,0.40,0.28,0.84,0.19,0.12,0.70,0.00,0.00,0.50,0.00,0.00]), [9,1,3]).step(-1, 1, 1),
|
||||
PuBu: ndarray(new Float64Array([1.00,0.97,0.98,0.93,0.91,0.95,0.82,0.82,0.90,0.65,0.74,0.86,0.45,0.66,0.81,0.21,0.56,0.75,0.02,0.44,0.69,0.02,0.35,0.55,0.01,0.22,0.35]), [9,1,3]).step(-1, 1, 1),
|
||||
BuPu: ndarray(new Float64Array([0.97,0.99,0.99,0.88,0.93,0.96,0.75,0.83,0.90,0.62,0.74,0.85,0.55,0.59,0.78,0.55,0.42,0.69,0.53,0.25,0.62,0.51,0.06,0.49,0.30,0.00,0.29]), [9,1,3]).step(-1, 1, 1),
|
||||
Oranges: ndarray(new Float64Array([1.00,0.96,0.92,1.00,0.90,0.81,0.99,0.82,0.64,0.99,0.68,0.42,0.99,0.55,0.24,0.95,0.41,0.07,0.85,0.28,0.00,0.65,0.21,0.01,0.50,0.15,0.02]), [9,1,3]).step(-1, 1, 1),
|
||||
BuGn: ndarray(new Float64Array([0.97,0.99,0.99,0.90,0.96,0.98,0.80,0.93,0.90,0.60,0.85,0.79,0.40,0.76,0.64,0.25,0.68,0.46,0.14,0.55,0.27,0.00,0.43,0.17,0.00,0.27,0.11]), [9,1,3]).step(-1, 1, 1),
|
||||
YlOrBr: ndarray(new Float64Array([1.00,1.00,0.90,1.00,0.97,0.74,1.00,0.89,0.57,1.00,0.77,0.31,1.00,0.60,0.16,0.93,0.44,0.08,0.80,0.30,0.01,0.60,0.20,0.02,0.40,0.15,0.02]), [9,1,3]).step(-1, 1, 1),
|
||||
YlGn: ndarray(new Float64Array([1.00,1.00,0.90,0.97,0.99,0.73,0.85,0.94,0.64,0.68,0.87,0.56,0.47,0.78,0.47,0.25,0.67,0.36,0.14,0.52,0.26,0.00,0.41,0.22,0.00,0.27,0.16]), [9,1,3]).step(-1, 1, 1),
|
||||
Reds: ndarray(new Float64Array([1.00,0.96,0.94,1.00,0.88,0.82,0.99,0.73,0.63,0.99,0.57,0.45,0.98,0.42,0.29,0.94,0.23,0.17,0.80,0.09,0.11,0.65,0.06,0.08,0.40,0.00,0.05]), [9,1,3]).step(-1, 1, 1),
|
||||
RdPu: ndarray(new Float64Array([1.00,0.97,0.95,0.99,0.88,0.87,0.99,0.77,0.75,0.98,0.62,0.71,0.97,0.41,0.63,0.87,0.20,0.59,0.68,0.00,0.49,0.48,0.00,0.47,0.29,0.00,0.42]), [9,1,3]).step(-1, 1, 1),
|
||||
Greens: ndarray(new Float64Array([0.97,0.99,0.96,0.90,0.96,0.88,0.78,0.91,0.75,0.63,0.85,0.61,0.45,0.77,0.46,0.25,0.67,0.36,0.14,0.55,0.27,0.00,0.43,0.17,0.00,0.27,0.11]), [9,1,3]).step(-1, 1, 1),
|
||||
YlGnBu: ndarray(new Float64Array([1.00,1.00,0.85,0.93,0.97,0.69,0.78,0.91,0.71,0.50,0.80,0.73,0.25,0.71,0.77,0.11,0.57,0.75,0.13,0.37,0.66,0.15,0.20,0.58,0.03,0.11,0.35]), [9,1,3]).step(-1, 1, 1),
|
||||
Purples: ndarray(new Float64Array([0.99,0.98,0.99,0.94,0.93,0.96,0.85,0.85,0.92,0.74,0.74,0.86,0.62,0.60,0.78,0.50,0.49,0.73,0.42,0.32,0.64,0.33,0.15,0.56,0.25,0.00,0.49]), [9,1,3]).step(-1, 1, 1),
|
||||
GnBu: ndarray(new Float64Array([0.97,0.99,0.94,0.88,0.95,0.86,0.80,0.92,0.77,0.66,0.87,0.71,0.48,0.80,0.77,0.31,0.70,0.83,0.17,0.55,0.75,0.03,0.41,0.67,0.03,0.25,0.51]), [9,1,3]).step(-1, 1, 1),
|
||||
Greys: ndarray(new Float64Array([1.00,1.00,1.00,0.94,0.94,0.94,0.85,0.85,0.85,0.74,0.74,0.74,0.59,0.59,0.59,0.45,0.45,0.45,0.32,0.32,0.32,0.15,0.15,0.15,0.00,0.00,0.00]), [9,1,3]).step(-1, 1, 1),
|
||||
YlOrRd: ndarray(new Float64Array([1.00,1.00,0.80,1.00,0.93,0.63,1.00,0.85,0.46,1.00,0.70,0.30,0.99,0.55,0.24,0.99,0.31,0.16,0.89,0.10,0.11,0.74,0.00,0.15,0.50,0.00,0.15]), [9,1,3]).step(-1, 1, 1),
|
||||
PuRd: ndarray(new Float64Array([0.97,0.96,0.98,0.91,0.88,0.94,0.83,0.73,0.85,0.79,0.58,0.78,0.87,0.40,0.69,0.91,0.16,0.54,0.81,0.07,0.34,0.60,0.00,0.26,0.40,0.00,0.12]), [9,1,3]).step(-1, 1, 1),
|
||||
Blues: ndarray(new Float64Array([0.97,0.98,1.00,0.87,0.92,0.97,0.78,0.86,0.94,0.62,0.79,0.88,0.42,0.68,0.84,0.26,0.57,0.78,0.13,0.44,0.71,0.03,0.32,0.61,0.03,0.19,0.42]), [9,1,3]).step(-1, 1, 1),
|
||||
PuBuGn: ndarray(new Float64Array([1.00,0.97,0.98,0.93,0.89,0.94,0.82,0.82,0.90,0.65,0.74,0.86,0.40,0.66,0.81,0.21,0.56,0.75,0.01,0.51,0.54,0.00,0.42,0.35,0.00,0.27,0.21]), [9,1,3]).step(-1, 1, 1),
|
||||
Spectral: ndarray(new Float64Array([0.62,0.00,0.26,0.84,0.24,0.31,0.96,0.43,0.26,0.99,0.68,0.38,1.00,0.88,0.55,1.00,1.00,0.75,0.90,0.96,0.60,0.67,0.87,0.64,0.40,0.76,0.65,0.20,0.53,0.74,0.37,0.31,0.64]), [11,1,3]).step(-1, 1, 1),
|
||||
RdYlGn: ndarray(new Float64Array([0.65,0.00,0.15,0.84,0.19,0.15,0.96,0.43,0.26,0.99,0.68,0.38,1.00,0.88,0.55,1.00,1.00,0.75,0.85,0.94,0.55,0.65,0.85,0.42,0.40,0.74,0.39,0.10,0.60,0.31,0.00,0.41,0.22]), [11,1,3]).step(-1, 1, 1),
|
||||
RdBu: ndarray(new Float64Array([0.40,0.00,0.12,0.70,0.09,0.17,0.84,0.38,0.30,0.96,0.65,0.51,0.99,0.86,0.78,0.97,0.97,0.97,0.82,0.90,0.94,0.57,0.77,0.87,0.26,0.58,0.76,0.13,0.40,0.67,0.02,0.19,0.38]), [11,1,3]).step(-1, 1, 1),
|
||||
PiYG: ndarray(new Float64Array([0.56,0.00,0.32,0.77,0.11,0.49,0.87,0.47,0.68,0.95,0.71,0.85,0.99,0.88,0.94,0.97,0.97,0.97,0.90,0.96,0.82,0.72,0.88,0.53,0.50,0.74,0.25,0.30,0.57,0.13,0.15,0.39,0.10]), [11,1,3]).step(-1, 1, 1),
|
||||
PRGn: ndarray(new Float64Array([0.25,0.00,0.29,0.46,0.16,0.51,0.60,0.44,0.67,0.76,0.65,0.81,0.91,0.83,0.91,0.97,0.97,0.97,0.85,0.94,0.83,0.65,0.86,0.63,0.35,0.68,0.38,0.11,0.47,0.22,0.00,0.27,0.11]), [11,1,3]).step(-1, 1, 1),
|
||||
RdYlBu: ndarray(new Float64Array([0.65,0.00,0.15,0.84,0.19,0.15,0.96,0.43,0.26,0.99,0.68,0.38,1.00,0.88,0.56,1.00,1.00,0.75,0.88,0.95,0.97,0.67,0.85,0.91,0.45,0.68,0.82,0.27,0.46,0.71,0.19,0.21,0.58]), [11,1,3]).step(-1, 1, 1),
|
||||
BrBG: ndarray(new Float64Array([0.33,0.19,0.02,0.55,0.32,0.04,0.75,0.51,0.18,0.87,0.76,0.49,0.96,0.91,0.76,0.96,0.96,0.96,0.78,0.92,0.90,0.50,0.80,0.76,0.21,0.59,0.56,0.00,0.40,0.37,0.00,0.24,0.19]), [11,1,3]).step(-1, 1, 1),
|
||||
RdGy: ndarray(new Float64Array([0.40,0.00,0.12,0.70,0.09,0.17,0.84,0.38,0.30,0.96,0.65,0.51,0.99,0.86,0.78,1.00,1.00,1.00,0.88,0.88,0.88,0.73,0.73,0.73,0.53,0.53,0.53,0.30,0.30,0.30,0.10,0.10,0.10]), [11,1,3]).step(-1, 1, 1),
|
||||
PuOr: ndarray(new Float64Array([0.50,0.23,0.03,0.70,0.35,0.02,0.88,0.51,0.08,0.99,0.72,0.39,1.00,0.88,0.71,0.97,0.97,0.97,0.85,0.85,0.92,0.70,0.67,0.82,0.50,0.45,0.67,0.33,0.15,0.53,0.18,0.00,0.29]), [11,1,3]).step(-1, 1, 1),
|
||||
Set2: ndarray(new Float64Array([0.40,0.76,0.65,0.99,0.55,0.38,0.55,0.63,0.80,0.91,0.54,0.76,0.65,0.85,0.33,1.00,0.85,0.18,0.90,0.77,0.58,0.70,0.70,0.70]), [8,1,3]).step(-1, 1, 1),
|
||||
Accent: ndarray(new Float64Array([0.50,0.79,0.50,0.75,0.68,0.83,0.99,0.75,0.53,1.00,1.00,0.60,0.22,0.42,0.69,0.94,0.01,0.50,0.75,0.36,0.09,0.40,0.40,0.40]), [8,1,3]).step(-1, 1, 1),
|
||||
Set1: ndarray(new Float64Array([0.89,0.10,0.11,0.22,0.49,0.72,0.30,0.69,0.29,0.60,0.31,0.64,1.00,0.50,0.00,1.00,1.00,0.20,0.65,0.34,0.16,0.97,0.51,0.75,0.60,0.60,0.60]), [9,1,3]).step(-1, 1, 1),
|
||||
Set3: ndarray(new Float64Array([0.55,0.83,0.78,1.00,1.00,0.70,0.75,0.73,0.85,0.98,0.50,0.45,0.50,0.69,0.83,0.99,0.71,0.38,0.70,0.87,0.41,0.99,0.80,0.90,0.85,0.85,0.85,0.74,0.50,0.74,0.80,0.92,0.77,1.00,0.93,0.44]), [12,1,3]).step(-1, 1, 1),
|
||||
Dark2: ndarray(new Float64Array([0.11,0.62,0.47,0.85,0.37,0.01,0.46,0.44,0.70,0.91,0.16,0.54,0.40,0.65,0.12,0.90,0.67,0.01,0.65,0.46,0.11,0.40,0.40,0.40]), [8,1,3]).step(-1, 1, 1),
|
||||
Paired: ndarray(new Float64Array([0.65,0.81,0.89,0.12,0.47,0.71,0.70,0.87,0.54,0.20,0.63,0.17,0.98,0.60,0.60,0.89,0.10,0.11,0.99,0.75,0.44,1.00,0.50,0.00,0.79,0.70,0.84,0.42,0.24,0.60,1.00,1.00,0.60,0.69,0.35,0.16]), [12,1,3]).step(-1, 1, 1),
|
||||
Pastel2: ndarray(new Float64Array([0.70,0.89,0.80,0.99,0.80,0.67,0.80,0.84,0.91,0.96,0.79,0.89,0.90,0.96,0.79,1.00,0.95,0.68,0.95,0.89,0.80,0.80,0.80,0.80]), [8,1,3]).step(-1, 1, 1),
|
||||
Pastel1: ndarray(new Float64Array([0.98,0.71,0.68,0.70,0.80,0.89,0.80,0.92,0.77,0.87,0.80,0.89,1.00,0.85,0.65,1.00,1.00,0.80,0.90,0.85,0.74,0.99,0.85,0.93,0.95,0.95,0.95]), [9,1,3]).step(-1, 1, 1),
|
||||
};
|
||||
44
cookbook-rn/src/examples/colorscale/index.js
Normal file
@ -0,0 +1,44 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { Shaders, Node, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import colorScales from "./colorScales"; export {colorScales};
|
||||
|
||||
const shaders = Shaders.create({
|
||||
colorify: {
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform sampler2D children, colorScale;
|
||||
float greyscale (vec3 c) { return 0.2125 * c.r + 0.7154 * c.g + 0.0721 * c.b; }
|
||||
void main() {
|
||||
vec4 original = texture2D(children, uv);
|
||||
vec4 newcolor = texture2D(colorScale, vec2(greyscale(original.rgb), 0.5));
|
||||
gl_FragColor = vec4(newcolor.rgb, original.a * newcolor.a);
|
||||
}` }
|
||||
});
|
||||
|
||||
export const Colorify =
|
||||
({ children, colorScale, interpolation }) =>
|
||||
<Node
|
||||
shader={shaders.colorify}
|
||||
uniformsOptions={{ colorScale: { interpolation } }}
|
||||
uniforms={{ colorScale, children }}
|
||||
/>;
|
||||
|
||||
export default class Example extends Component {
|
||||
render() {
|
||||
const { interpolation, color } = this.props;
|
||||
return (
|
||||
<Surface width={400} height={300}>
|
||||
<Colorify colorScale={colorScales[color]} interpolation={interpolation}>
|
||||
{require("../../iPKTONG.jpg")}
|
||||
</Colorify>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
static defaultProps = {
|
||||
interpolation: "linear",
|
||||
color: Object.keys(colorScales)[0],
|
||||
};
|
||||
}
|
||||
27
cookbook-rn/src/examples/colorscale/meta.js
Normal file
@ -0,0 +1,27 @@
|
||||
import React from "react";
|
||||
import colorScales from "./colorScales";
|
||||
import makeSelect from "../../toolbox/makeSelect";
|
||||
import { LinearCopy, NearestCopy } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
|
||||
export const title = "color mapping with gradient texture";
|
||||
export const description = "A gradient texture defines the color mapping of the image greyscale.";
|
||||
|
||||
export const toolbox = [
|
||||
{ prop: "color",
|
||||
title: "color scale",
|
||||
Editor: makeSelect(Object.keys(colorScales).map(cs =>
|
||||
({ key: cs, label: cs }))) },
|
||||
{ prop: "interpolation",
|
||||
Editor: makeSelect([
|
||||
{ key: "linear", label: "linear interpolation" },
|
||||
{ key: "nearest", label: "nearest interpolation" },
|
||||
]) }
|
||||
];
|
||||
|
||||
export const ToolboxFooter = ({ color, interpolation }) =>
|
||||
<Surface width={400} height={20}>
|
||||
{ interpolation==="linear"
|
||||
? <LinearCopy>{colorScales[color]}</LinearCopy>
|
||||
: <NearestCopy>{colorScales[color]}</NearestCopy> }
|
||||
</Surface>;
|
||||
226
cookbook-rn/src/examples/demodesert/index.js
Normal file
@ -0,0 +1,226 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import { Shaders, Node, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import timeLoop from "../../HOC/timeLoop";
|
||||
import shadertoyTex17jpg from "./shadertoy-tex17.jpg";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
desertPassage: {
|
||||
// from https://www.shadertoy.com/view/XtyGzc
|
||||
frag: GLSL`
|
||||
precision mediump float;
|
||||
varying vec2 uv;
|
||||
uniform float iGlobalTime;
|
||||
uniform sampler2D iChannel0;
|
||||
#define FAR 80.
|
||||
mat2 rot2( float th ){ vec2 a = sin(vec2(1.5707963, 0) + th); return mat2(a, -a.y, a.x); }
|
||||
float hash( float n ){ return fract(cos(n)*45758.5453); }
|
||||
float hash( vec3 p ){ return fract(sin(dot(p, vec3(7, 157, 113)))*45758.5453); }
|
||||
float drawObject(in vec3 p){ p = fract(p)-.5; return dot(p, p); }
|
||||
float cellTile(in vec3 p){
|
||||
vec4 d;
|
||||
d.x = drawObject(p - vec3(.81, .62, .53));
|
||||
p.xy = vec2(p.y-p.x, p.y + p.x)*.7071;
|
||||
d.y = drawObject(p - vec3(.39, .2, .11));
|
||||
p.yz = vec2(p.z-p.y, p.z + p.y)*.7071;
|
||||
d.z = drawObject(p - vec3(.62, .24, .06));
|
||||
p.xz = vec2(p.z-p.x, p.z + p.x)*.7071;
|
||||
d.w = drawObject(p - vec3(.2, .82, .64));
|
||||
d.xy = min(d.xz, d.yw);
|
||||
return min(d.x, d.y)*2.66;
|
||||
}
|
||||
vec2 path(in float z){ return vec2(20.*sin(z * .04), 4.*cos(z * .09) + 3.*(sin(z*.025) - 1.)); }
|
||||
float surfFunc(in vec3 p){
|
||||
float c = cellTile(p/6.);
|
||||
return mix(c, cos(c*6.283*2.)*.5 + .5, .125);
|
||||
}
|
||||
float smin(float a, float b , float s){
|
||||
float h = clamp( 0.5 + 0.5*(b-a)/s, 0. , 1.);
|
||||
return mix(b, a, h) - h*(1.0-h)*s;
|
||||
}
|
||||
float smax(float a, float b, float s){
|
||||
float h = clamp( 0.5 + 0.5*(a-b)/s, 0., 1.);
|
||||
return mix(b, a, h) + h*(1.0-h)*s;
|
||||
}
|
||||
float map(vec3 p){
|
||||
float sf = surfFunc(p);
|
||||
float cav = dot(cos(p*3.14159265/8.), sin(p.yzx*3.14159265/8.)) + 2.;
|
||||
p.xy -= path(p.z);
|
||||
float tun = 1.5 - length(p.xy*vec2(1, .4));
|
||||
tun = smax(tun, 1.-cav, 2.) + .75 + (.5-sf);
|
||||
float gr = p.y + 7. - cav*.5 + (.5-sf)*.5;
|
||||
float rf = p.y - 15.;
|
||||
return smax(smin(tun, gr, .1), rf, 1.);
|
||||
}
|
||||
float trace(in vec3 ro, in vec3 rd){
|
||||
float t = 0., h;
|
||||
for(int i=0; i<128; i++){
|
||||
h = map(ro+rd*t);
|
||||
if(abs(h)<0.002*(t*.25 + 1.) || t>FAR) break;
|
||||
t += h*.8;
|
||||
}
|
||||
return min(t, FAR);
|
||||
}
|
||||
vec3 normal(in vec3 p)
|
||||
{
|
||||
vec2 e = vec2(-1., 1.)*0.001;
|
||||
return normalize(e.yxx*map(p + e.yxx) + e.xxy*map(p + e.xxy) +
|
||||
e.xyx*map(p + e.xyx) + e.yyy*map(p + e.yyy) );
|
||||
}
|
||||
vec3 tex3D( sampler2D t, in vec3 p, in vec3 n ){
|
||||
n = max(abs(n) - .2, .001);
|
||||
n /= (n.x + n.y + n.z );
|
||||
p = (texture2D(t, p.yz)*n.x + texture2D(t, p.zx)*n.y + texture2D(t, p.xy)*n.z).xyz;
|
||||
return p*p;
|
||||
}
|
||||
vec3 doBumpMap( sampler2D tx, in vec3 p, in vec3 n, float bf){
|
||||
const vec2 e = vec2(0.001, 0);
|
||||
mat3 m = mat3( tex3D(tx, p - e.xyy, n), tex3D(tx, p - e.yxy, n), tex3D(tx, p - e.yyx, n));
|
||||
vec3 g = vec3(0.299, 0.587, 0.114)*m;
|
||||
g = (g - dot(tex3D(tx, p , n), vec3(0.299, 0.587, 0.114)) )/e.x; g -= n*dot(n, g);
|
||||
return normalize( n + g*bf );
|
||||
}
|
||||
float n3D(in vec3 p){
|
||||
const vec3 s = vec3(7, 157, 113);
|
||||
vec3 ip = floor(p); p -= ip;
|
||||
vec4 h = vec4(0., s.yz, s.y + s.z) + dot(ip, s);
|
||||
p = p*p*(3. - 2.*p);
|
||||
h = mix(fract(sin(h)*43758.5453), fract(sin(h + s.x)*43758.5453), p.x);
|
||||
h.xy = mix(h.xz, h.yw, p.y);
|
||||
return mix(h.x, h.y, p.z);
|
||||
}
|
||||
float bumpSurf3D( in vec3 p){
|
||||
float bmp = cellTile(p/3.)*.8 + cellTile(p)*.2;
|
||||
float ns = n3D(p*6. - bmp*6.);
|
||||
return mix(bmp, 1. - abs(ns-.333)/.667, .05);
|
||||
}
|
||||
vec3 doBumpMap(in vec3 p, in vec3 nor, float bumpfactor){
|
||||
const vec2 e = vec2(0.001, 0);
|
||||
float ref = bumpSurf3D(p);
|
||||
vec3 grad = (vec3(bumpSurf3D(p - e.xyy),
|
||||
bumpSurf3D(p - e.yxy),
|
||||
bumpSurf3D(p - e.yyx) )-ref)/e.x;
|
||||
grad -= nor*dot(nor, grad);
|
||||
return normalize( nor + grad*bumpfactor );
|
||||
}
|
||||
float softShadow(in vec3 ro, in vec3 rd, in float start, in float end, in float k){
|
||||
float shade = 1.0;
|
||||
const int maxIterationsShad = 10;
|
||||
float dist = start;
|
||||
float stepDist = end/float(maxIterationsShad);
|
||||
for (int i=0; i<maxIterationsShad; i++){
|
||||
float h = map(ro + rd*dist);
|
||||
shade = min(shade, smoothstep(0., 1., k*h/dist));
|
||||
dist += clamp(h, .2, stepDist);
|
||||
if (abs(h)<0.001 || dist > end) break;
|
||||
}
|
||||
return min(max(shade, 0.) + .1, 1.);
|
||||
}
|
||||
float calculateAO( in vec3 p, in vec3 n)
|
||||
{
|
||||
float ao = 0.0, l;
|
||||
const float nbIte = 6.0;
|
||||
const float maxDist = 3.;
|
||||
for(float i=1.; i< nbIte+.5; i++ ){
|
||||
l = (i*.66 + hash(i)*.34)/nbIte*maxDist;
|
||||
ao += (l - map( p + n*l ))/(1.+ l);
|
||||
}
|
||||
return clamp( 1.-ao/nbIte, 0., 1.);
|
||||
}
|
||||
vec3 getSky(){ return vec3(2., 1.4, .7); }
|
||||
float trig3(in vec3 p){
|
||||
p = cos(p*2. + (cos(p.yzx) + 1.)*1.57);
|
||||
return dot(p, vec3(0.1666)) + 0.5;
|
||||
}
|
||||
float trigNoise3D(in vec3 p){
|
||||
const mat3 m3RotTheta = mat3(0.25, -0.866, 0.433, 0.9665, 0.25, -0.2455127, -0.058, 0.433, 0.899519 )*1.5;
|
||||
float res = 0.;
|
||||
float t = trig3(p*3.14159265);
|
||||
p += (t);
|
||||
p = m3RotTheta*p;
|
||||
res += t;
|
||||
t = trig3(p*3.14159265);
|
||||
p += (t)*0.7071;
|
||||
p = m3RotTheta*p;
|
||||
res += t*0.7071;
|
||||
t = trig3(p*3.14159265);
|
||||
res += t*0.5;
|
||||
return res/2.2071;
|
||||
}
|
||||
float hash31(vec3 p){ return fract(sin(dot(p, vec3(127.1, 311.7, 74.7)))*43758.5453); }
|
||||
float getMist(in vec3 ro, in vec3 rd, in vec3 lp, in float t){
|
||||
float mist = 0.;
|
||||
ro += rd*t/3.;
|
||||
for (int i = 0; i<3; i++){
|
||||
float sDi = length(lp-ro)/FAR;
|
||||
float sAtt = 1./(1. + sDi*0.1 + sDi*sDi*0.01);
|
||||
mist += trigNoise3D(ro/2.)*sAtt;
|
||||
ro += rd*t/3.;
|
||||
}
|
||||
return clamp(mist/1.5 + hash31(ro)*0.1-0.05, 0., 1.);
|
||||
}
|
||||
void main() {
|
||||
vec2 u = uv * 2.0 - 1.0;
|
||||
vec3 ro = vec3(0, 0, iGlobalTime*8.);
|
||||
vec3 lookAt = ro + vec3(0, 0, .5);
|
||||
ro.xy += path(ro.z);
|
||||
lookAt.xy += path(lookAt.z);
|
||||
float FOV = 3.14159265/2.5;
|
||||
vec3 forward = normalize(lookAt - ro);
|
||||
vec3 right = normalize(vec3(forward.z, 0, -forward.x ));
|
||||
vec3 up = cross(forward, right);
|
||||
vec3 rd = normalize(forward + FOV*u.x*right + FOV*u.y*up);
|
||||
rd.xy = rot2( path(lookAt.z).x/64. )*rd.xy;
|
||||
vec3 lp = vec3(FAR*.5, FAR, FAR) + vec3(0, 0, ro.z);
|
||||
float t = trace(ro, rd);
|
||||
vec3 sky = getSky();
|
||||
vec3 col = sky;
|
||||
vec3 sp = ro+t*rd;
|
||||
float pathHeight = sp.y-path(sp.z).y;
|
||||
if (t < FAR){
|
||||
vec3 sn = normal( sp );
|
||||
vec3 ld = lp-sp;
|
||||
ld /= max(length(ld), 0.001);
|
||||
const float tSize = 1./4.;
|
||||
sn = doBumpMap(sp, sn, .75/(1. + t/FAR*.25));
|
||||
float bf = (pathHeight + 5. < 0.)? .05: .025;
|
||||
sn = doBumpMap(iChannel0, sp*tSize, sn, bf/(1. + t/FAR));
|
||||
float shd = softShadow(sp, ld, 0.05, FAR, 8.);
|
||||
float ao = calculateAO(sp, sn);
|
||||
float dif = max( dot( ld, sn ), 0.0);
|
||||
float spe = pow(max( dot( reflect(-ld, sn), -rd ), 0.0 ), 5.);
|
||||
float fre = clamp(1.0 + dot(rd, sn), 0.0, 1.0);
|
||||
float Schlick = pow( 1. - max(dot(rd, normalize(rd + ld)), 0.), 5.0);
|
||||
float fre2 = mix(.2, 1., Schlick);
|
||||
float amb = fre*fre2*.7 + .05;
|
||||
col = clamp(mix(vec3(1.152, 0.4275,.153), vec3(.225, 0.05985, 0.0153), -sn.y*.5 + pathHeight*.5 + 1.75), vec3(.9, 0.534375, 0.239), vec3(.9, .855, .765));
|
||||
col = smoothstep(-.5, 1., tex3D(iChannel0, sp*tSize, sn)*2.)*(col + vec3(.225, .21375, .19125));
|
||||
col += smoothstep(0., 1., -pathHeight - 5.5)*fre*.25;
|
||||
col += getSky()*fre*fre2;
|
||||
col = (col*(dif + .1) + vec3(1)*fre2*spe)*shd*ao + amb*pow(col, vec3(2.));
|
||||
}
|
||||
float dust = getMist(ro, rd, lp, t)*(1.-clamp((pathHeight - 5.)*.125, 0., 1.));
|
||||
sky = getSky()*mix(1., .75, dust);
|
||||
col = mix(col, sky, min(t*t*1.5/FAR/FAR, 1.));
|
||||
u = uv;
|
||||
col = min(col, 1.)*pow( 16.0*u.x*u.y*(1.0-u.x)*(1.0-u.y) , .125);
|
||||
gl_FragColor = vec4(sqrt(clamp(col, 0., 1.)), 1);
|
||||
}` }
|
||||
});
|
||||
|
||||
const DesertPassage = ({ time }) =>
|
||||
<Node
|
||||
shader={shaders.desertPassage}
|
||||
uniforms={{
|
||||
iGlobalTime: time / 1000,
|
||||
iChannel0: shadertoyTex17jpg,
|
||||
}}
|
||||
/>
|
||||
|
||||
export const DesertPassageLoop = timeLoop(DesertPassage, { frameRate: 30 });
|
||||
|
||||
export default () =>
|
||||
<Surface width={400} height={400}>
|
||||
<DesertPassageLoop />
|
||||
</Surface>
|
||||
1
cookbook-rn/src/examples/demodesert/meta.js
Normal file
@ -0,0 +1 @@
|
||||
export const title = "a Shadertoy more advanced example";
|
||||
BIN
cookbook-rn/src/examples/demodesert/shadertoy-tex17.jpg
Normal file
|
After Width: | Height: | Size: 298 KiB |
160
cookbook-rn/src/examples/demodesertcrt/index.js
Normal file
@ -0,0 +1,160 @@
|
||||
//@flow
|
||||
import React, { Component, PureComponent } from "react";
|
||||
import { View, Button } from "react-native";
|
||||
import {Shaders, Node, GLSL, Bus, connectSize} from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import {DesertPassageLoop} from "../demodesert";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
crt: {
|
||||
// adapted from http://bit.ly/2eR1iKi
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform sampler2D rubyTexture;
|
||||
uniform vec2 rubyInputSize;
|
||||
uniform vec2 rubyOutputSize;
|
||||
uniform vec2 rubyTextureSize;
|
||||
uniform float distortion;
|
||||
#define TEX2D(c) pow(texture2D(rubyTexture, (c)), vec4(inputGamma))
|
||||
#define FIX(c) max(abs(c), 1e-6);
|
||||
#define PI 3.141592653589
|
||||
#define phase 0.0
|
||||
#define inputGamma 2.2
|
||||
#define outputGamma 2.5
|
||||
vec2 radialDistortion(vec2 coord) {
|
||||
coord *= rubyTextureSize / rubyInputSize;
|
||||
vec2 cc = coord - 0.5;
|
||||
float dist = dot(cc, cc) * distortion;
|
||||
return (coord + cc * (1.0 + dist) * dist) * rubyInputSize / rubyTextureSize;
|
||||
}
|
||||
vec4 scanlineWeights(float distance, vec4 color)
|
||||
{
|
||||
vec4 wid = 2.0 + 2.0 * pow(color, vec4(4.0));
|
||||
vec4 weights = vec4(distance * 3.333333);
|
||||
return 0.51 * exp(-pow(weights * sqrt(2.0 / wid), wid)) / (0.18 + 0.06 * wid);
|
||||
}
|
||||
void main()
|
||||
{
|
||||
vec2 one = 1.0 / rubyTextureSize;
|
||||
vec2 xy = radialDistortion(uv.xy);
|
||||
vec2 uv_ratio = fract(xy * rubyTextureSize) - vec2(0.5);
|
||||
xy = (floor(xy * rubyTextureSize) + vec2(0.5)) / rubyTextureSize;
|
||||
vec4 coeffs = PI * vec4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x);
|
||||
coeffs = FIX(coeffs);
|
||||
coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs);
|
||||
coeffs /= dot(coeffs, vec4(1.0));
|
||||
vec4 col = clamp(coeffs.x * TEX2D(xy + vec2(-one.x, 0.0)) + coeffs.y * TEX2D(xy) + coeffs.z * TEX2D(xy + vec2(one.x, 0.0)) + coeffs.w * TEX2D(xy + vec2(2.0 * one.x, 0.0)), 0.0, 1.0);
|
||||
vec4 col2 = clamp(coeffs.x * TEX2D(xy + vec2(-one.x, one.y)) + coeffs.y * TEX2D(xy + vec2(0.0, one.y)) + coeffs.z * TEX2D(xy + one) + coeffs.w * TEX2D(xy + vec2(2.0 * one.x, one.y)), 0.0, 1.0);
|
||||
vec4 weights = scanlineWeights(abs(uv_ratio.y) , col);
|
||||
vec4 weights2 = scanlineWeights(1.0 - uv_ratio.y, col2);
|
||||
vec3 mul_res = (col * weights + col2 * weights2).xyz;
|
||||
float mod_factor = uv.x * rubyOutputSize.x * rubyTextureSize.x / rubyInputSize.x;
|
||||
vec3 dotMaskWeights = mix(
|
||||
vec3(1.05, 0.75, 1.05),
|
||||
vec3(0.75, 1.05, 0.75),
|
||||
floor(mod(mod_factor, 2.0))
|
||||
);
|
||||
mul_res *= dotMaskWeights;
|
||||
mul_res = pow(mul_res, vec3(1.0 / (2.0 * inputGamma - outputGamma)));
|
||||
gl_FragColor = vec4(mul_res, 1.0);
|
||||
}` },
|
||||
copy: {
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform sampler2D t;
|
||||
void main(){
|
||||
gl_FragColor=texture2D(t,uv);
|
||||
}`,
|
||||
}
|
||||
});
|
||||
|
||||
class CRT extends Component {
|
||||
props: {
|
||||
children?: any,
|
||||
distortion: number,
|
||||
inSize: [number, number],
|
||||
outSize: [number, number],
|
||||
texSize: [number, number],
|
||||
};
|
||||
render() {
|
||||
const { children, inSize, outSize, texSize, distortion } = this.props;
|
||||
return <Node
|
||||
shader={shaders.crt}
|
||||
uniforms={{
|
||||
rubyTexture: children,
|
||||
rubyInputSize: inSize,
|
||||
rubyOutputSize: outSize,
|
||||
rubyTextureSize: texSize,
|
||||
distortion,
|
||||
}}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
const Desert = connectSize(DesertPassageLoop);
|
||||
|
||||
class ShowCaptured extends PureComponent {
|
||||
render() {
|
||||
const {t} = this.props;
|
||||
return <Surface width={200} height={200}>
|
||||
<Node shader={shaders.copy} uniforms={{ t }} />
|
||||
</Surface>;
|
||||
}
|
||||
}
|
||||
|
||||
export default class Example extends Component {
|
||||
state = {
|
||||
surfacePixels: null,
|
||||
desertPixels: null,
|
||||
};
|
||||
|
||||
onCapture = () =>
|
||||
this.setState({
|
||||
surfacePixels: this.refs.surface.capture(),
|
||||
desertPixels: this.refs.desert.capture(),
|
||||
});
|
||||
|
||||
render() {
|
||||
const { distortion } = this.props;
|
||||
const { surfacePixels, desertPixels } = this.state;
|
||||
return (
|
||||
<View>
|
||||
<Surface ref="surface"
|
||||
width={400}
|
||||
height={400}
|
||||
webglContextAttributes={{ preserveDrawingBuffer: true }}>
|
||||
|
||||
<Bus ref="desert">{/* we use a Bus to have a ref for capture */}
|
||||
<Desert width={128} height={128} />
|
||||
</Bus>
|
||||
|
||||
<CRT
|
||||
distortion={distortion}
|
||||
texSize={[ 128, 128 ]}
|
||||
inSize={[ 128, 128 ]}
|
||||
outSize={[ 400, 400 ]}>
|
||||
{() => this.refs.desert}
|
||||
</CRT>
|
||||
|
||||
</Surface>
|
||||
|
||||
<View className="buttons">
|
||||
<Button
|
||||
onPress={this.onCapture}
|
||||
title="capture"
|
||||
/>
|
||||
</View>
|
||||
<View className="snaps">
|
||||
<ShowCaptured t={surfacePixels} />
|
||||
<ShowCaptured t={desertPixels} />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
distortion: 0.2
|
||||
};
|
||||
}
|
||||
9
cookbook-rn/src/examples/demodesertcrt/meta.js
Normal file
@ -0,0 +1,9 @@
|
||||
import makeFloatSlider from "../../toolbox/makeFloatSlider";
|
||||
|
||||
export const title = "Doom Shadertoy + CRT effect + snapshot()";
|
||||
|
||||
export const toolbox = [
|
||||
{ prop: "distortion",
|
||||
title: "Distortion",
|
||||
Editor: makeFloatSlider(0, 1, 0.01) },
|
||||
];
|
||||
37
cookbook-rn/src/examples/demotunnel/index.js
Normal file
@ -0,0 +1,37 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import { Shaders, Node, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import timeLoop from "../../HOC/timeLoop";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
squareTunnel: {
|
||||
// from https://en.wikipedia.org/wiki/Shadertoy
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform float iGlobalTime;
|
||||
void main() {
|
||||
vec2 p = 2.0 * uv - vec2(1.0);
|
||||
float a = atan(p.y,p.x);
|
||||
float r = pow( pow(p.x*p.x,4.0) + pow(p.y*p.y,4.0), 1.0/8.0 );
|
||||
vec2 uv = vec2( 1.0/r + 0.2*iGlobalTime, a );
|
||||
float f = cos(12.0*uv.x)*cos(6.0*uv.y);
|
||||
vec3 col = 0.5 + 0.5*sin( 3.1416*f + vec3(0.0,0.5,1.0) );
|
||||
col = col*r;
|
||||
gl_FragColor = vec4( col, 1.0 );
|
||||
}` }
|
||||
});
|
||||
|
||||
const SquareTunnel = ({ time }) =>
|
||||
<Node
|
||||
shader={shaders.squareTunnel}
|
||||
uniforms={{ iGlobalTime: time / 1000 }}
|
||||
/>
|
||||
|
||||
const DesertPassageLoop = timeLoop(SquareTunnel);
|
||||
|
||||
export default() =>
|
||||
<Surface width={400} height={400}>
|
||||
<DesertPassageLoop />
|
||||
</Surface>
|
||||
1
cookbook-rn/src/examples/demotunnel/meta.js
Normal file
@ -0,0 +1 @@
|
||||
export const title = "a Shadertoy simple example";
|
||||
31
cookbook-rn/src/examples/diamondanim/index.js
Normal file
@ -0,0 +1,31 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import { Shaders, Node, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import { DiamondCrop } from "../diamondcrop";
|
||||
import timeLoop from "../../HOC/timeLoop";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
helloRed: {
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform float red;
|
||||
void main() {
|
||||
gl_FragColor = vec4(red, uv.x, uv.y, 1.0);
|
||||
}` }
|
||||
});
|
||||
|
||||
const HelloGLAnimated = timeLoop( ({ time }) =>
|
||||
<Node
|
||||
shader={shaders.helloRed}
|
||||
uniforms={{ red: Math.cos(time / 100) }}
|
||||
/>
|
||||
);
|
||||
|
||||
export default () =>
|
||||
<Surface width={300} height={300}>
|
||||
<DiamondCrop>
|
||||
<HelloGLAnimated blue={0.8} />
|
||||
</DiamondCrop>
|
||||
</Surface>;
|
||||
1
cookbook-rn/src/examples/diamondanim/meta.js
Normal file
@ -0,0 +1 @@
|
||||
export const title = "animated HelloGL (red) + DiamondCrop";
|
||||
34
cookbook-rn/src/examples/diamondcrop/index.js
Normal file
@ -0,0 +1,34 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { Shaders, Node, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
DiamondCrop: {
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform sampler2D t;
|
||||
void main() {
|
||||
gl_FragColor = mix(
|
||||
texture2D(t, uv),
|
||||
vec4(0.0),
|
||||
step(0.5, abs(uv.x - 0.5) + abs(uv.y - 0.5))
|
||||
);
|
||||
}` },
|
||||
});
|
||||
|
||||
export const DiamondCrop = ({ children: t }) =>
|
||||
<Node shader={shaders.DiamondCrop} uniforms={{ t }} />;
|
||||
|
||||
export default class Example extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Surface width={300} height={300}>
|
||||
<DiamondCrop>
|
||||
{require("../../5EOyTDQ.jpg")}
|
||||
</DiamondCrop>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
}
|
||||
1
cookbook-rn/src/examples/diamondcrop/meta.js
Normal file
@ -0,0 +1 @@
|
||||
export const title = "DiamondCrop on an image texture";
|
||||
17
cookbook-rn/src/examples/diamondhello/index.js
Normal file
@ -0,0 +1,17 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import { DiamondCrop } from "../diamondcrop";
|
||||
import { HelloBlue } from "../helloblue";
|
||||
|
||||
export default class Example extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Surface width={300} height={300}>
|
||||
<DiamondCrop>
|
||||
<HelloBlue blue={0.8} />
|
||||
</DiamondCrop>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
}
|
||||
1
cookbook-rn/src/examples/diamondhello/meta.js
Normal file
@ -0,0 +1 @@
|
||||
export const title = "HelloGL composed with DiamondCrop";
|
||||
66
cookbook-rn/src/examples/distortion/index.js
Normal file
@ -0,0 +1,66 @@
|
||||
import React, { Component } from "react";
|
||||
import { Shaders, Node, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import timeLoop from "../../HOC/timeLoop";
|
||||
import respondToTouchPosition from "../../HOC/respondToTouchPosition";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
vignetteColorSeparationDistortion: {
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform sampler2D t;
|
||||
uniform vec2 mouse;
|
||||
uniform float time, amp, freq, moving;
|
||||
vec2 lookup (vec2 offset, float amp2) {
|
||||
return mod(
|
||||
uv + amp2 * amp * vec2(
|
||||
cos(freq*(uv.x+offset.x)+time),
|
||||
sin(freq*(uv.y+offset.x)+time))
|
||||
+ vec2(
|
||||
moving * time/10.0,
|
||||
0.0),
|
||||
vec2(1.0));
|
||||
}
|
||||
void main() {
|
||||
float dist = distance(uv, mouse);
|
||||
float amp2 = pow(1.0 - dist, 2.0);
|
||||
float colorSeparation = 0.02 * mix(amp2, 1.0, 0.5);
|
||||
vec2 orientation = vec2(1.0, 0.0);
|
||||
float a = (1.0-min(0.95, pow(1.8 * distance(uv, mouse), 4.0) +
|
||||
0.5 * pow(distance(fract(50.0 * uv.y), 0.5), 2.0)));
|
||||
gl_FragColor = vec4(a * vec3(
|
||||
texture2D(t, lookup(colorSeparation * orientation, amp2)).r,
|
||||
texture2D(t, lookup(-colorSeparation * orientation, amp2)).g,
|
||||
texture2D(t, lookup(vec2(0.0), amp2)).b),
|
||||
1.0);
|
||||
}` }
|
||||
});
|
||||
|
||||
|
||||
const Vignette = timeLoop(({ children: t, time, mouse }) =>
|
||||
<Node
|
||||
shader={shaders.vignetteColorSeparationDistortion}
|
||||
uniforms={{
|
||||
t,
|
||||
time: time / 1000, // seconds is better for float precision
|
||||
mouse,
|
||||
freq: 10 + 2 * Math.sin(0.0007*time),
|
||||
amp: 0.05 + Math.max(0, 0.03*Math.cos(0.001 * time)),
|
||||
moving: 0,
|
||||
}}
|
||||
/>);
|
||||
|
||||
export default respondToTouchPosition(class Example extends Component {
|
||||
props: { touchPosition: { x: number, y: number } };
|
||||
render() {
|
||||
const { touchPosition: {x, y} } = this.props;
|
||||
return (
|
||||
<Surface width={500} height={400}>
|
||||
<Vignette mouse={[ x, y ]}>
|
||||
{require("../../2VP5osy.jpg")}
|
||||
</Vignette>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
});
|
||||
2
cookbook-rn/src/examples/distortion/meta.js
Normal file
@ -0,0 +1,2 @@
|
||||
export const title = "Crazy distortion effect on an image";
|
||||
export const description = "Vignette color separation distortion + touch responsive";
|
||||
17
cookbook-rn/src/examples/gen.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
echo "// This file is generated by \`npm run generate-examples\` from index.txt"
|
||||
while read ex
|
||||
do
|
||||
if [ ! -z $ex ] && [ -d $ex ]
|
||||
then
|
||||
echo "import ${ex}_E from './$ex';";
|
||||
echo "import * as ${ex}_m from './$ex/meta';";
|
||||
echo "export const $ex={ Example: ${ex}_E, ...${ex}_m };"
|
||||
elif [ ! -z _TODO_$ex ] && [ -d _TODO_$ex ]
|
||||
then
|
||||
echo "import * as ${ex}_m from './_TODO_$ex/meta';";
|
||||
echo "export const $ex={ Example: null, ...${ex}_m };"
|
||||
else
|
||||
echo "$ex not found" 1>&2;
|
||||
fi
|
||||
done < index.txt;
|
||||
94
cookbook-rn/src/examples/glsledit/index.js
Normal file
@ -0,0 +1,94 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { View, Text, StyleSheet } from "react-native";
|
||||
import { Node, Visitor, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import timeLoop from "../../HOC/timeLoop";
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
compileRoot: {
|
||||
flexDirection: "row",
|
||||
},
|
||||
compile: {
|
||||
padding: 6,
|
||||
backgroundColor: "#000",
|
||||
color: "#c22",
|
||||
fontSize: 10,
|
||||
lineHeight: 18,
|
||||
fontFamily: "Courier New",
|
||||
},
|
||||
compileError: {
|
||||
color: "#c22",
|
||||
},
|
||||
compileSuccess: {
|
||||
color: "#2c2",
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
const Preview = timeLoop(({ frag, visitor, time }) =>
|
||||
<Surface width={500} height={200} visitor={visitor}>
|
||||
<Node shader={{ frag }} uniforms={{ time: time / 1000 }} />
|
||||
</Surface>);
|
||||
|
||||
class DisplayError extends Component {
|
||||
props: { error: ?string };
|
||||
render() {
|
||||
const { error } = this.props;
|
||||
if (!error) return <Text style={[ styles.compile, styles.compileSuccess ]}>
|
||||
Compilation success!
|
||||
</Text>;
|
||||
let err = error.message;
|
||||
const i = err.indexOf("ERROR:");
|
||||
if (i!==-1) err = "line "+err.slice(i + 9);
|
||||
return <Text style={[ styles.compile, styles.compileError ]}>{err}</Text>;
|
||||
}
|
||||
}
|
||||
|
||||
export default class Example extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
const visitor = new Visitor();
|
||||
visitor.onSurfaceDrawError = (error: Error) => this.setState({ error });
|
||||
visitor.onSurfaceDrawEnd = () => this.setState({ error: null });
|
||||
this.state = { error: null, visitor };
|
||||
}
|
||||
|
||||
render() {
|
||||
const { frag } = this.props;
|
||||
const { error, visitor } = this.state;
|
||||
return (
|
||||
<View>
|
||||
<Preview frag={frag} visitor={visitor} />
|
||||
<DisplayError error={error} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
props: { frag: string };
|
||||
state: { error: ?Error, visitor: Visitor };
|
||||
static defaultProps = { // adapted from http://glslsandbox.com/e#27937.0
|
||||
frag: GLSL`precision highp float;
|
||||
varying vec2 uv;
|
||||
|
||||
uniform float time;
|
||||
|
||||
void main() {
|
||||
float amnt;
|
||||
float nd;
|
||||
vec4 cbuff = vec4(0.0);
|
||||
for(float i=0.0; i<5.0;i++){
|
||||
nd = sin(3.17*0.8*uv.x + (i*0.1+sin(+time)*0.2) + time)*0.8+0.1 + uv.x;
|
||||
amnt = 1.0/abs(nd-uv.y)*0.01;
|
||||
cbuff += vec4(amnt, amnt*0.3 , amnt*uv.y, 90.0);
|
||||
}
|
||||
for(float i=0.0; i<1.0;i++){
|
||||
nd = sin(3.14*2.0*uv.y + i*40.5 + time)*90.3*(uv.y+80.3)+0.5;
|
||||
amnt = 1.0/abs(nd-uv.x)*0.015;
|
||||
cbuff += vec4(amnt*0.2, amnt*0.2 , amnt*uv.x, 1.0);
|
||||
}
|
||||
gl_FragColor = cbuff;
|
||||
}
|
||||
`
|
||||
};
|
||||
}
|
||||
32
cookbook-rn/src/examples/glsledit/meta.js
Normal file
@ -0,0 +1,32 @@
|
||||
import { StyleSheet } from "react-native";
|
||||
export const title = "GLSL live editor";
|
||||
import makeTextArea from "../../toolbox/makeTextArea";
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
editor: {
|
||||
flex: 1,
|
||||
height: 400,
|
||||
padding: 10,
|
||||
margin: 0,
|
||||
backgroundColor: "#282c34",
|
||||
color: "#ABB2BF",
|
||||
fontSize: 10,
|
||||
lineHeight: 1.5,
|
||||
fontFamily: "Courier New",
|
||||
},
|
||||
});
|
||||
|
||||
export const overrideStyles = StyleSheet.create({
|
||||
toolbox: {
|
||||
paddingBottom: 0,
|
||||
},
|
||||
field: {
|
||||
paddingVertical: 0,
|
||||
paddingHorizontal: 0,
|
||||
}
|
||||
});
|
||||
|
||||
export const toolbox = [
|
||||
{ prop: "frag",
|
||||
Editor: makeTextArea(styles.editor) }
|
||||
];
|
||||
83
cookbook-rn/src/examples/gol/index.js
Normal file
@ -0,0 +1,83 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import {Backbuffer,Shaders,Node,GLSL,NearestCopy} from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import timeLoop from "../../HOC/timeLoop";
|
||||
|
||||
export const shaders = Shaders.create({
|
||||
InitGameOfLife: {
|
||||
// returns white or black randomly
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
// i
|
||||
varying vec2 uv;
|
||||
float random (vec2 uv) {
|
||||
return fract(sin(dot(uv, vec2(12.9898,78.233))) * 43758.5453);
|
||||
}
|
||||
// i
|
||||
void main() {
|
||||
gl_FragColor = vec4(vec3(step(0.5, random(uv))), 1.0);
|
||||
}`
|
||||
},
|
||||
GameOfLife: {
|
||||
// implement Game Of Life.
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform float size;
|
||||
uniform sampler2D t; // the previous world state
|
||||
void main() {
|
||||
float prev = step(0.5, texture2D(t, uv).r);
|
||||
float c = 1.0 / size;
|
||||
float sum =
|
||||
step(0.5, texture2D(t, uv + vec2(-1.0, -1.0)*c).r) +
|
||||
step(0.5, texture2D(t, uv + vec2(-1.0, 0.0)*c).r) +
|
||||
step(0.5, texture2D(t, uv + vec2(-1.0, 1.0)*c).r) +
|
||||
step(0.5, texture2D(t, uv + vec2( 0.0, 1.0)*c).r) +
|
||||
step(0.5, texture2D(t, uv + vec2( 1.0, 1.0)*c).r) +
|
||||
step(0.5, texture2D(t, uv + vec2( 1.0, 0.0)*c).r) +
|
||||
step(0.5, texture2D(t, uv + vec2( 1.0, -1.0)*c).r) +
|
||||
step(0.5, texture2D(t, uv + vec2( 0.0, -1.0)*c).r);
|
||||
float next = prev==1.0 && sum >= 2.0 && sum <= 3.0 || sum == 3.0 ? 1.0 : 0.0;
|
||||
gl_FragColor = vec4(vec3(next), 1.0);
|
||||
}`
|
||||
}
|
||||
});
|
||||
|
||||
const refreshEveryTicks = 20;
|
||||
|
||||
export const GameOfLife = ({ tick }) => {
|
||||
// Changing size is "destructive" and will reset the Game of Life state
|
||||
const size = 16 * (1+Math.floor(tick/refreshEveryTicks));
|
||||
// However, we can conditionally change shader/uniforms,
|
||||
// React reconciliation will preserve the same <Node> instance,
|
||||
// and our Game of Life state will get preserved!
|
||||
return tick%refreshEveryTicks===0
|
||||
? <Node
|
||||
shader={shaders.InitGameOfLife}
|
||||
width={size}
|
||||
height={size}
|
||||
backbuffering // makes Node holding 2 fbos that get swapped each draw time
|
||||
sync // force <Node> to draw in sync each componentDidUpdate time
|
||||
/>
|
||||
: <Node
|
||||
shader={shaders.GameOfLife}
|
||||
width={size}
|
||||
height={size}
|
||||
backbuffering
|
||||
sync
|
||||
uniforms={{
|
||||
t: Backbuffer, // Use previous frame buffer as a texture
|
||||
size,
|
||||
}}
|
||||
/>;
|
||||
};
|
||||
|
||||
const GameOfLifeLoop = timeLoop(GameOfLife, { refreshRate: 20 });
|
||||
|
||||
export default () =>
|
||||
<Surface width={384} height={384}>
|
||||
<NearestCopy>
|
||||
<GameOfLifeLoop />
|
||||
</NearestCopy>
|
||||
</Surface>
|
||||
1
cookbook-rn/src/examples/gol/meta.js
Normal file
@ -0,0 +1 @@
|
||||
export const title = "GameOfLife";
|
||||
BIN
cookbook-rn/src/examples/golglider/glider-gun-64.png
Normal file
|
After Width: | Height: | Size: 178 B |
37
cookbook-rn/src/examples/golglider/index.js
Normal file
@ -0,0 +1,37 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { Backbuffer, Node, NearestCopy } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import {shaders} from "../gol";
|
||||
import timeLoop from "../../HOC/timeLoop";
|
||||
import gliderGunImage from "./glider-gun-64.png";
|
||||
|
||||
const GameOfLifeLoop = timeLoop(({ tick, size }) =>
|
||||
<Node
|
||||
shader={shaders.GameOfLife}
|
||||
width={size}
|
||||
height={size}
|
||||
backbuffering
|
||||
sync
|
||||
uniforms={{
|
||||
t: tick===0 ? gliderGunImage : Backbuffer,
|
||||
size,
|
||||
}}
|
||||
/>, { refreshRate: 20 });
|
||||
|
||||
export default class Example extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Surface
|
||||
width={500}
|
||||
height={500}
|
||||
preload={[ // preload textures before starting rendering
|
||||
gliderGunImage
|
||||
]}>
|
||||
<NearestCopy>
|
||||
<GameOfLifeLoop size={64} />
|
||||
</NearestCopy>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
}
|
||||
2
cookbook-rn/src/examples/golglider/meta.js
Normal file
@ -0,0 +1,2 @@
|
||||
export const title = "GameOfLife is initialized with a glider texture";
|
||||
export const description = "Game of Life init with an image";
|
||||
45
cookbook-rn/src/examples/golrot/index.js
Normal file
@ -0,0 +1,45 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import { Shaders, Node, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import timeLoop from "../../HOC/timeLoop";
|
||||
import {GameOfLife} from "../gol";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
Rotating: {
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform float angle, scale;
|
||||
uniform sampler2D children;
|
||||
void main() {
|
||||
mat2 rotation = mat2(cos(angle), -sin(angle), sin(angle), cos(angle));
|
||||
vec2 p = (uv - vec2(0.5)) * rotation / scale + vec2(0.5);
|
||||
gl_FragColor =
|
||||
p.x < 0.0 || p.x > 1.0 || p.y < 0.0 || p.y > 1.0
|
||||
? vec4(0.0)
|
||||
: texture2D(children, p);
|
||||
}` }
|
||||
});
|
||||
|
||||
export const Rotating = ({ angle, scale, children }) =>
|
||||
<Node
|
||||
shader={shaders.Rotating}
|
||||
uniformsOptions={{ children: { interpolation: "nearest" } }}
|
||||
uniforms={{ angle, scale, children }}
|
||||
/>;
|
||||
|
||||
const RotatingLoop = timeLoop(({ time, children }) => Rotating({
|
||||
angle: (time / 1000) % (2 * Math.PI),
|
||||
scale: 0.6 + 0.15 * Math.cos(time / 500),
|
||||
children,
|
||||
}));
|
||||
|
||||
const GameOfLifeLoop = timeLoop(GameOfLife, { refreshRate: 5 });
|
||||
|
||||
export default () =>
|
||||
<Surface width={500} height={500}>
|
||||
<RotatingLoop>
|
||||
<GameOfLifeLoop />
|
||||
</RotatingLoop>
|
||||
</Surface>;
|
||||
2
cookbook-rn/src/examples/golrot/meta.js
Normal file
@ -0,0 +1,2 @@
|
||||
export const title = "Rotating GameOfLife. 2 loops";
|
||||
export const description = "Compose Game of Life with Rotation";
|
||||
36
cookbook-rn/src/examples/golrotscu/index.js
Normal file
@ -0,0 +1,36 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import timeLoop from "../../HOC/timeLoop";
|
||||
import {GameOfLife} from "../gol";
|
||||
import {Rotating} from "../golrot";
|
||||
|
||||
class PureGameOfLife extends Component {
|
||||
shouldComponentUpdate ({ tick }) { // only tick should trigger redraw
|
||||
return tick !== this.props.tick;
|
||||
}
|
||||
render() {
|
||||
return <GameOfLife tick={this.props.tick} />;
|
||||
}
|
||||
}
|
||||
|
||||
const RotatingGameOfLife = ({ time }) =>
|
||||
<Rotating
|
||||
angle={(time / 1000) % (2 * Math.PI)}
|
||||
scale={0.6 + 0.15 * Math.cos(time / 500)}>
|
||||
|
||||
<PureGameOfLife tick={Math.floor(time / 200)} />
|
||||
|
||||
</Rotating>;
|
||||
|
||||
export const RotatingGameOfLifeLoop = timeLoop(RotatingGameOfLife);
|
||||
|
||||
export default class Example extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Surface width={500} height={500}>
|
||||
<RotatingGameOfLifeLoop />
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
}
|
||||
2
cookbook-rn/src/examples/golrotscu/meta.js
Normal file
@ -0,0 +1,2 @@
|
||||
export const title = "Rotating GameOfLife with sCU";
|
||||
export const description = "Single update loop and shouldComponentUpdate";
|
||||
56
cookbook-rn/src/examples/gradients/index.js
Normal file
@ -0,0 +1,56 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import { Shaders, Node, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import timeLoop from "../../HOC/timeLoop";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
gradients: { frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform vec4 colors[3];
|
||||
uniform vec2 particles[3];
|
||||
void main () {
|
||||
vec4 sum = vec4(0.0);
|
||||
for (int i=0; i<3; i++) {
|
||||
vec4 c = colors[i];
|
||||
vec2 p = particles[i];
|
||||
float d = c.a * smoothstep(0.6, 0.2, distance(p, uv));
|
||||
sum += d * vec4(c.a * c.rgb, c.a);
|
||||
}
|
||||
if (sum.a > 1.0) {
|
||||
sum.rgb /= sum.a;
|
||||
sum.a = 1.0;
|
||||
}
|
||||
gl_FragColor = vec4(sum.a * sum.rgb, 1.0);
|
||||
}`}
|
||||
});
|
||||
|
||||
// Alternative syntax using React stateless function component
|
||||
const Gradients = ({ time }) =>
|
||||
<Node
|
||||
shader={shaders.gradients}
|
||||
uniforms={{
|
||||
colors: [
|
||||
[ Math.cos(0.002*time), Math.sin(0.002*time), 0.2, 1 ],
|
||||
[ Math.sin(0.002*time), -Math.cos(0.002*time), 0.1, 1 ],
|
||||
[ 0.3, Math.sin(3+0.002*time), Math.cos(1+0.003*time), 1 ]
|
||||
],
|
||||
particles: [
|
||||
[ 0.3, 0.3 ],
|
||||
[ 0.7, 0.5 ],
|
||||
[ 0.4, 0.9 ]
|
||||
]
|
||||
}}
|
||||
/>;
|
||||
|
||||
const GradientsLoop = timeLoop(Gradients);
|
||||
|
||||
export default () =>
|
||||
<Surface width={300} height={300}>
|
||||
<GradientsLoop />
|
||||
</Surface>;
|
||||
|
||||
// NB: don't abuse the uniforms array:
|
||||
// it's not meant to be used with lot of objects.
|
||||
// GLSL 1 also don't support variable length in loops.
|
||||
2
cookbook-rn/src/examples/gradients/meta.js
Normal file
@ -0,0 +1,2 @@
|
||||
export const title = "Rotating radial gradients";
|
||||
export const description = "More advanced animation";
|
||||
69
cookbook-rn/src/examples/heart/index.js
Normal file
@ -0,0 +1,69 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { TouchableWithoutFeedback } from "react-native";
|
||||
import { Shaders, Node, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import {Motion, spring} from "react-motion";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
Heart: { // inspired from http://glslsandbox.com/e#29521.0
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform sampler2D image;
|
||||
uniform vec3 color;
|
||||
uniform float over, toggle;
|
||||
void main() {
|
||||
float scale = 1.0 - 0.1 * over - 0.8 * toggle;
|
||||
vec2 offset = vec2(0.0, -0.3 - 0.1 * over - 0.7 * toggle);
|
||||
vec2 p = scale * (2.0 * uv - 1.0 + offset);
|
||||
float a = atan(p.x, p.y) / ${Math.PI/* \o/ */};
|
||||
float r = length(p);
|
||||
float h = abs(a);
|
||||
float d = (13.0*h - 22.0*h*h + 10.0*h*h*h - 0.3 * (1.0-over))/(6.0-5.0*h);
|
||||
float f = step(r,d) * pow(max(1.0-r/d, 0.0),0.25);
|
||||
vec3 t = texture2D(image, uv).rgb;
|
||||
vec3 c = mix(color * (1.0 + 0.6 * t), t, min(0.8 * over + toggle, 1.0));
|
||||
gl_FragColor = vec4(mix(vec3(1.0), c, f), 1.0);
|
||||
}`
|
||||
}
|
||||
});
|
||||
|
||||
class InteractiveHeart extends Component {
|
||||
state = { over: 0, toggle: 0 };
|
||||
onPressIn = () => this.setState({ over: 1 });
|
||||
onPressOut = () => this.setState({ over: 0 });
|
||||
onPress = () => this.setState({
|
||||
toggle: this.state.toggle ? 0 : 1
|
||||
});
|
||||
render() {
|
||||
const { color, image } = this.props;
|
||||
const { over, toggle } = this.state;
|
||||
return (
|
||||
<TouchableWithoutFeedback
|
||||
onPress={this.onPress}
|
||||
onPressIn={this.onPressIn}
|
||||
onPressOut={this.onPressOut}>
|
||||
<Surface width={300} height={300}>
|
||||
<Motion
|
||||
defaultStyle={{ over, toggle }}
|
||||
style={{
|
||||
over: spring(over, [150, 15]),
|
||||
toggle: spring(toggle, [150, 15])
|
||||
}}>{ ({ over, toggle }) =>
|
||||
<Node
|
||||
shader={shaders.Heart}
|
||||
uniforms={{ color, image, over, toggle }}
|
||||
/>
|
||||
}</Motion>
|
||||
</Surface>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default () =>
|
||||
<InteractiveHeart
|
||||
color={[ 1, 0, 0 ]}
|
||||
image={require("../../GQo1KWq.jpg")}
|
||||
/>;
|
||||
1
cookbook-rn/src/examples/heart/meta.js
Normal file
@ -0,0 +1 @@
|
||||
export const title = "Heart animation";
|
||||
36
cookbook-rn/src/examples/helloblue/index.js
Normal file
@ -0,0 +1,36 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { Shaders, Node, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
helloBlue: {
|
||||
// uniforms are variables from JS. We pipe blue uniform into blue output color
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform float blue;
|
||||
void main() {
|
||||
gl_FragColor = vec4(uv.x, uv.y, blue, 1.0);
|
||||
}` }
|
||||
});
|
||||
|
||||
// We can make a <HelloBlue blue={0.5} /> that will render the concrete <Node/>
|
||||
export class HelloBlue extends Component {
|
||||
render() {
|
||||
const { blue } = this.props;
|
||||
return <Node shader={shaders.helloBlue} uniforms={{ blue }} />;
|
||||
}
|
||||
}
|
||||
|
||||
// Our example will pass the slider value to HelloBlue
|
||||
export default class Example extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Surface width={300} height={300}>
|
||||
<HelloBlue blue={this.props.blue} />
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
static defaultProps = { blue: 0.5 };
|
||||
}
|
||||
9
cookbook-rn/src/examples/helloblue/meta.js
Normal file
@ -0,0 +1,9 @@
|
||||
import makeFloatSlider from "../../toolbox/makeFloatSlider";
|
||||
|
||||
export const title = "Hello GL blue";
|
||||
|
||||
export const toolbox = [
|
||||
{ prop: "blue",
|
||||
title: "Blue Color",
|
||||
Editor: makeFloatSlider(0, 1, 0.01) },
|
||||
];
|
||||
21
cookbook-rn/src/examples/helloblueanim/index.js
Normal file
@ -0,0 +1,21 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { Surface } from "gl-react-native";
|
||||
|
||||
// Reuse that previous HelloBlue component to animate it...
|
||||
import { HelloBlue } from "../helloblue";
|
||||
|
||||
// timeLoop is an utility that animates a component.
|
||||
// in a requestAnimationFrame loop and provide a time and tick prop
|
||||
import timeLoop from "../../HOC/timeLoop";
|
||||
|
||||
export default timeLoop(class Example extends Component {
|
||||
render() {
|
||||
const { time } = this.props;
|
||||
return (
|
||||
<Surface width={300} height={300}>
|
||||
<HelloBlue blue={0.5 + 0.5 * Math.cos(time / 500)} />
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
});
|
||||
1
cookbook-rn/src/examples/helloblueanim/meta.js
Normal file
@ -0,0 +1 @@
|
||||
export const title = "Hello GL blue animated";
|
||||
34
cookbook-rn/src/examples/hellogl/index.js
Normal file
@ -0,0 +1,34 @@
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { Shaders, Node, GLSL } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
|
||||
// in gl-react you need to statically define "shaders":
|
||||
const shaders = Shaders.create({
|
||||
helloGL: {
|
||||
// This is our first fragment shader in GLSL language (OpenGL Shading Language)
|
||||
// (GLSL code gets compiled and run on the GPU)
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
void main() {
|
||||
gl_FragColor = vec4(uv.x, uv.y, 0.5, 1.0);
|
||||
}`
|
||||
// the main() function is called FOR EACH PIXELS
|
||||
// the varying uv is a vec2 where x and y respectively varying from 0.0 to 1.0.
|
||||
// we set in output the pixel color using the vec4(r,g,b,a) format.
|
||||
// see [GLSL_ES_Specification_1.0.17](http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf)
|
||||
}
|
||||
});
|
||||
|
||||
export default class Example extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Surface width={300} height={300}>
|
||||
<Node shader={shaders.helloGL} />
|
||||
</Surface>
|
||||
);
|
||||
// Surface creates the canvas, an area of pixels where you can draw.
|
||||
// Node instanciates a "shader program" with the fragment shader defined above.
|
||||
}
|
||||
}
|
||||
1
cookbook-rn/src/examples/hellogl/meta.js
Normal file
@ -0,0 +1 @@
|
||||
export const title = "Hello GL";
|
||||
615
cookbook-rn/src/examples/ibex/index.js
Normal file
@ -0,0 +1,615 @@
|
||||
/**
|
||||
* This celullar automaton is extracted from a game I wrote in 2014 for JS13K:
|
||||
* https://github.com/gre/ibex
|
||||
*
|
||||
* Technical article: http://greweb.me/2014/09/ibex-cellular-automata/
|
||||
*/
|
||||
|
||||
//@flow
|
||||
import React, { Component } from "react";
|
||||
import { Shaders, Node, GLSL, Backbuffer } from "gl-react";
|
||||
import { Surface } from "gl-react-native";
|
||||
import ndarray from "ndarray";
|
||||
import timeLoop from "../../HOC/timeLoop";
|
||||
|
||||
const shaders = Shaders.create({
|
||||
IBEXRender: {
|
||||
frag: GLSL`
|
||||
precision highp float;
|
||||
varying vec2 uv;
|
||||
uniform vec2 size;
|
||||
uniform sampler2D state;
|
||||
uniform vec3 CL[9];
|
||||
|
||||
float rand(vec2 co){
|
||||
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
|
||||
}
|
||||
vec3 colorFor (int e) {
|
||||
if(e==0) return CL[0];
|
||||
if(e==1) return CL[1];
|
||||
if(e==2) return CL[2];
|
||||
if(e==3) return CL[3];
|
||||
if(e==4) return CL[4];
|
||||
if(e==5) return CL[5];
|
||||
if(e==6) return CL[6];
|
||||
if(e==7) return CL[7];
|
||||
return CL[8];
|
||||
}
|
||||
int getState (vec2 pos) {
|
||||
vec2 uv = (floor(pos) + 0.5) / size;
|
||||
bool outOfBound = uv.x<0.0||uv.x>1.0||uv.y<0.0||uv.y>1.0;
|
||||
if (outOfBound) return pos.y < 0.0 ? 1 : 0;
|
||||
float cel = texture2D(state, uv).r;
|
||||
return int(floor(.5 + 9. * cel));
|
||||
}
|
||||
vec3 stateColorPass (int e, vec2 pos) {
|
||||
return (
|
||||
mix(1.0, rand(pos), 0.05*float(e==1) + 0.2*float(e==8)) +
|
||||
float(e==8) * (
|
||||
step(0.97, rand(pos)) * vec3(3.0, 0.0, 0.0) +
|
||||
step(rand(pos), 0.02) * vec3(1.5, -0.5, 0.5)
|
||||
)
|
||||
) * colorFor(e);
|
||||
}
|
||||
void main(){
|
||||
vec2 statePos = uv * size;
|
||||
vec2 statePosFloor = floor(statePos);
|
||||
vec3 stateColor = stateColorPass(getState(statePosFloor), statePosFloor);
|
||||
vec3 c = stateColor;
|
||||
vec2 pixelPos = fract(statePos);
|
||||
vec3 pixelColor = -vec3(0.03) * (pixelPos.x - pixelPos.y);
|
||||
c += pixelColor;
|
||||
gl_FragColor = vec4(c, 1.0);
|
||||
}
|
||||
`
|
||||
},
|
||||
IBEXLogic: {
|
||||
frag: GLSL`
|
||||
#define RAND (S_=vec2(rand(S_), rand(S_+9.))).x
|
||||
#define AnyADJ(e) (NW==e||SE==e||NE==e||SW==e||NN==e||SS==e||EE==e||WW==e)
|
||||
precision highp float;
|
||||
int A = 0;
|
||||
int E = 1;
|
||||
int F = 2;
|
||||
int W = 3;
|
||||
int V = 4;
|
||||
int S = 5;
|
||||
int Al = 6;
|
||||
int Ar = 7;
|
||||
int G = 8;
|
||||
varying vec2 uv;
|
||||
uniform vec2 SZ;
|
||||
uniform float SD;
|
||||
uniform float TI;
|
||||
uniform float TS;
|
||||
uniform float ST;
|
||||
uniform sampler2D state;
|
||||
uniform bool RU;
|
||||
uniform bool draw;
|
||||
uniform ivec2 DP;
|
||||
uniform float DR;
|
||||
uniform int DO;
|
||||
uniform float forestGrowFactor;
|
||||
int get (int x_, int y_) {
|
||||
vec2 u = (SZ * uv + vec2(x_, y_)) / SZ;
|
||||
return (u.x < 0.0 || u.x >= 1.0 || u.y < 0.0 || u.y >= 1.0) ? 0 :
|
||||
int(floor(.5 + 9. * texture2D(state, u).r));
|
||||
}
|
||||
bool between (float f, float a, float b) {
|
||||
return a <= f && f <= b;
|
||||
}
|
||||
float rand(vec2 co){
|
||||
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
|
||||
}
|
||||
float grassDistrib (vec2 p) {
|
||||
return mix(
|
||||
rand(vec2(p.x)),
|
||||
0.5*(1.0+(cos(sin(p.y*0.01 + p.x * 0.05) +
|
||||
(1.0 + 0.3*sin(p.x*0.01)) * p.y * 0.08))),
|
||||
0.6
|
||||
);
|
||||
}
|
||||
bool hellTriggerPosition (vec2 p) {
|
||||
if (TS==0.0) return false;
|
||||
float hellTickStart = 800.0;
|
||||
float hellTickInterv = 70.0;
|
||||
float hellSize = 5.0;
|
||||
float dt = TI - TS - hellTickStart;
|
||||
float x = floor(dt / hellTickInterv);
|
||||
float y = (dt - x * hellTickInterv);
|
||||
return distance(vec2(2.0 * (hellSize * x - ST), hellSize * y), p) <= hellSize;
|
||||
}
|
||||
void main () {
|
||||
vec2 p = uv * SZ;
|
||||
vec2 S_ = p + 0.001 * TI;
|
||||
int NW = get(-1, 1);
|
||||
int NN = get( 0, 1);
|
||||
int NE = get( 1, 1);
|
||||
int WW = get(-1, 0);
|
||||
int CC = get( 0, 0);
|
||||
int EE = get( 1, 0);
|
||||
int SW = get(-1,-1);
|
||||
int SS = get( 0,-1);
|
||||
int SE = get( 1,-1);
|
||||
bool prevIsSolid = CC==E||CC==G||CC==V||CC==S;
|
||||
int r = A;
|
||||
int grassMaxHeight = int(20.0 * pow(grassDistrib(p), 1.3));
|
||||
float rainRelativeTime = mod(TI, 300.0);
|
||||
float volcRelativeTime = mod(TI, 25.0);
|
||||
if (
|
||||
-0.05 * float(NW==W) + -0.40 * float(NN==W) + -0.05 * float(NE==W) +
|
||||
-0.50 * float(WW==W) + -0.50 * float(CC==W) + -0.50 * float(EE==W) +
|
||||
0.35 * float(SW==F) + 0.90 * float(SS==F) + 0.35 * float(SE==F)
|
||||
>= 0.9 - 0.6 * RAND
|
||||
||
|
||||
CC == F && RAND < 0.9 && AnyADJ(G)
|
||||
) {
|
||||
r = F;
|
||||
}
|
||||
if (
|
||||
between(
|
||||
0.3 * float(NW==W) + 0.9 * float(NN==W) + 0.3 * float(NE==W) +
|
||||
0.1 * float(WW==W) + -0.3 * float(CC==F) + 0.1 * float(EE==W) +
|
||||
-0.3 * float(SS==F)
|
||||
,
|
||||
0.9 - 0.6 * RAND,
|
||||
1.4 + 0.3 * RAND
|
||||
)
|
||||
||
|
||||
!prevIsSolid &&
|
||||
RAND < 0.98 &&
|
||||
( (WW==W||NW==W) && SW==E || (EE==W||NE==W) && SE==E )
|
||||
||
|
||||
!prevIsSolid &&
|
||||
p.y >= SZ.y-1.0 &&
|
||||
rainRelativeTime < 100.0 &&
|
||||
between(
|
||||
p.x -
|
||||
(rand(vec2(SD*0.7 + TI - rainRelativeTime)) * SZ.x)
|
||||
,
|
||||
0.0,
|
||||
100.0 * rand(vec2(SD + TI - rainRelativeTime))
|
||||
)
|
||||
||
|
||||
!prevIsSolid && (
|
||||
0.9 * float(NW==S) + 1.0 * float(NN==S) + 0.9 * float(NE==S) +
|
||||
0.7 * float(WW==S) + 0.7 * float(EE==S)
|
||||
>= 1.0 - 0.3 * RAND
|
||||
)
|
||||
) {
|
||||
r = W;
|
||||
}
|
||||
if (CC == E) {
|
||||
if (!(WW==A && EE==A)) r = E;
|
||||
if (
|
||||
RAND < 0.3 && (
|
||||
1.0 * float(NW==W) + 1.2 * float(NN==W) + 1.0 * float(NE==W) +
|
||||
0.5 * float(WW==W) + 0.5 * float(EE==W) +
|
||||
0.3 * float(SW==W) + 0.2 * float(SS==W) + 0.3 * float(SE==W)
|
||||
>= 3.0 - 2.5 * RAND
|
||||
)
|
||||
||
|
||||
RAND < 0.01 && ( WW==S || NN==S || EE==S )
|
||||
) {
|
||||
r = S;
|
||||
}
|
||||
if (
|
||||
RAND < 0.01 + 0.02 * smoothstep(500.0, 5000.0, ST + p.x) &&
|
||||
( int(WW==V) + int(SS==V) + int(EE==V) + int(SE==V) + int(SW==V) > 1 )
|
||||
) {
|
||||
r = V;
|
||||
}
|
||||
}
|
||||
if (grassMaxHeight > 0) {
|
||||
if (CC == G) {
|
||||
r = G;
|
||||
if (
|
||||
CC == G &&
|
||||
RAND < 0.9 && (
|
||||
AnyADJ(F) ||
|
||||
AnyADJ(V)
|
||||
)) {
|
||||
r = F;
|
||||
}
|
||||
}
|
||||
else if (!prevIsSolid && (AnyADJ(E) || AnyADJ(G) || AnyADJ(S))) {
|
||||
if (RAND < 0.03 * forestGrowFactor &&
|
||||
get(0, -grassMaxHeight) != G && (
|
||||
SS==G && RAND < 0.07 ||
|
||||
SS==E && RAND < 0.02 ||
|
||||
AnyADJ(W) ||
|
||||
AnyADJ(S)
|
||||
)
|
||||
) {
|
||||
r = G;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((!prevIsSolid || CC==F) && SS==V) {
|
||||
r = F;
|
||||
}
|
||||
if (CC == V) {
|
||||
r = V;
|
||||
if (
|
||||
NW==W || NN==W || NE==W || EE==W || WW==W
|
||||
) {
|
||||
r = RAND < 0.8 ? S : E;
|
||||
}
|
||||
if (
|
||||
RAND<0.005 &&
|
||||
( int(SW==F||SW==V) + int(SS==F||SS==V) + int(SE==F||SE==V) < 2 )
|
||||
) {
|
||||
r = E;
|
||||
}
|
||||
if (
|
||||
int(NW==S) + int(SE==S) + int(NE==S) + int(SW==S) +
|
||||
int(NN==S) + int(SS==S) + int(EE==S) + int(WW==S)
|
||||
> 1
|
||||
) {
|
||||
r = RAND < 0.2 ? V : (RAND < 0.8 ? S : E);
|
||||
}
|
||||
}
|
||||
if (prevIsSolid &&
|
||||
p.y <= 2.0 &&
|
||||
volcRelativeTime <= 1.0 &&
|
||||
RAND < 0.3 &&
|
||||
between(
|
||||
p.x -
|
||||
rand(vec2(SD*0.01 + TI - volcRelativeTime)) * SZ.x
|
||||
,
|
||||
0.0,
|
||||
10.0 * rand(vec2(SD*0.07 + TI - volcRelativeTime))
|
||||
)
|
||||
) {
|
||||
r = V;
|
||||
}
|
||||
if (CC == S) {
|
||||
r = S;
|
||||
if (
|
||||
RAND<0.06 &&
|
||||
( int(NW==W||NW==S) + int(NN==W||NN==S) + int(NE==W||NE==S) < 1 )
|
||||
|
||||
||
|
||||
( EE==F || WW==F || SS==F || SW==F || SE==F )
|
||||
) {
|
||||
r = E;
|
||||
}
|
||||
if (AnyADJ(V)) {
|
||||
r = RAND < 0.15 ? V : (RAND < 0.6 ? S : E);
|
||||
}
|
||||
}
|
||||
if (r == A) {
|
||||
if (RAND < 0.00001) r = Al;
|
||||
if (RAND < 0.00001) r = Ar;
|
||||
}
|
||||
|
||||
int wind = r==Al ? Al : r == Ar ? Ar : 0;
|
||||
float f =
|
||||
(-0.1+0.05*(RAND-0.5)) * float(NW==Ar) + 0.12 * float(NE==Al) +
|
||||
-0.65 * float(WW==Ar) + 0.65 * float(EE==Al) +
|
||||
-0.1 * float(SW==Ar) + (0.2+0.05*(RAND-0.5)) * float(SE==Al) ;
|
||||
|
||||
if (between(f, 0.4 * RAND, 0.95)) {
|
||||
wind = Al;
|
||||
}
|
||||
else if (between(f, -0.95, -0.4 * RAND)) {
|
||||
wind = Ar;
|
||||
}
|
||||
if (wind != 0) {
|
||||
if (r == A) {
|
||||
r = wind;
|
||||
}
|
||||
else if(r == F) {
|
||||
if (RAND < 0.4) r = wind;
|
||||
}
|
||||
else if (r == W) {
|
||||
if (RAND < 0.1) r = wind;
|
||||
}
|
||||
}
|
||||
if (draw) {
|
||||
vec2 pos = floor(p);
|
||||
if (distance(pos, vec2(DP)) <= DR) {
|
||||
if (DO == W) {
|
||||
if (prevIsSolid && CC!=G) {
|
||||
r = S;
|
||||
}
|
||||
else if (!prevIsSolid && mod(pos.x + pos.y, 2.0)==0.0) {
|
||||
r = W;
|
||||
}
|
||||
}
|
||||
else if (DO == F) {
|
||||
r = prevIsSolid ? V : F;
|
||||
}
|
||||
else {
|
||||
r = DO;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hellTriggerPosition(p)) {
|
||||
r = prevIsSolid ? V : F;
|
||||
}
|
||||
if (!RU) {
|
||||
if (r == F || r == W|| r == G) r = A;
|
||||
if (r == V || r == S) r = E;
|
||||
}
|
||||
gl_FragColor = vec4(float(r) / 9.0, 0.0, 0.0, 1.0);
|
||||
}`
|
||||
}
|
||||
});
|
||||
|
||||
class IBEXLogic extends Component {
|
||||
state = {
|
||||
seed: Math.random(),
|
||||
};
|
||||
shouldComponentUpdate({ tick }) {
|
||||
return tick !== this.props.tick;
|
||||
}
|
||||
render() {
|
||||
const {
|
||||
size,
|
||||
tick,
|
||||
initialState,
|
||||
forestGrowFactor,
|
||||
waterFactor,
|
||||
fireFactor,
|
||||
} = this.props;
|
||||
const { seed } = this.state;
|
||||
let draw=false, drawPosition=[0,0], drawRadius=0, drawElement=0;
|
||||
|
||||
let w = Math.random() < waterFactor, f = Math.random() < fireFactor;
|
||||
if (w && f) {
|
||||
if (Math.random() * waterFactor - Math.random() * fireFactor > 0) {
|
||||
f = false;
|
||||
}
|
||||
else {
|
||||
w = false;
|
||||
}
|
||||
}
|
||||
if (w) {
|
||||
draw = true;
|
||||
drawPosition=[
|
||||
size[0]*Math.random(),
|
||||
size[1]*(0.8 + 0.2 * Math.random()),
|
||||
];
|
||||
drawRadius = 4;
|
||||
drawElement = 3;
|
||||
console.log(drawElement, drawPosition, drawPosition);
|
||||
}
|
||||
else if (f) {
|
||||
draw = true;
|
||||
drawPosition=[
|
||||
size[0]*Math.random(),
|
||||
0,
|
||||
];
|
||||
drawRadius = 4;
|
||||
drawElement = 2;
|
||||
console.log(drawElement, drawPosition, drawPosition);
|
||||
}
|
||||
|
||||
return <Node
|
||||
shader={shaders.IBEXLogic}
|
||||
sync
|
||||
backbuffering
|
||||
uniformsOptions={{ state: { interpolation: "nearest" } }}
|
||||
uniforms={{
|
||||
state: tick===0 ? initialState : Backbuffer,
|
||||
SZ: size,
|
||||
SD: seed,
|
||||
TI: tick,
|
||||
TS: 0, // tick start
|
||||
RU: true, // logic running
|
||||
ST: true, // render started
|
||||
draw,
|
||||
DP: drawPosition, // draw position
|
||||
DR: drawRadius, // draw radius
|
||||
DO: drawElement, // the element that is being drawn
|
||||
forestGrowFactor,
|
||||
}}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
var colors = [
|
||||
[0.11, 0.16, 0.23], // 0: air
|
||||
[0.74, 0.66, 0.51], // 1: earth
|
||||
[0.84, 0.17, 0.08], // 2: fire
|
||||
[0.40, 0.75, 0.90], // 3: water
|
||||
[0.60, 0.00, 0.00], // 4: volcano (fire spawner)
|
||||
[0.30, 0.60, 0.70], // 5: source (water spawner)
|
||||
[0.15, 0.20, 0.27], // 6: wind left
|
||||
[0.07, 0.12, 0.19], // 7: wind right
|
||||
[0.20, 0.60, 0.20] // 8: grass (forest)
|
||||
];
|
||||
|
||||
const IBEXRender = ({ size, children: state }) =>
|
||||
<Node
|
||||
shader={shaders.IBEXRender}
|
||||
uniformsOptions={{ state: { interpolation: "nearest" } }}
|
||||
uniforms={{
|
||||
state,
|
||||
size,
|
||||
CL: colors,
|
||||
}}
|
||||
/>;
|
||||
|
||||
const Game = timeLoop(class extends Component {
|
||||
state = {
|
||||
tick: 0,
|
||||
lastTickTime: this.props.time,
|
||||
};
|
||||
|
||||
componentWillReceiveProps({ time, speed }) {
|
||||
this.setState(({ tick, lastTickTime }) => {
|
||||
const delta = 1000/speed;
|
||||
if (time-lastTickTime > delta) {
|
||||
return {
|
||||
tick: tick + 1,
|
||||
lastTickTime: lastTickTime + delta,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
size,
|
||||
initialState,
|
||||
forestGrowFactor,
|
||||
waterFactor,
|
||||
fireFactor
|
||||
} = this.props;
|
||||
const {
|
||||
tick,
|
||||
} = this.state;
|
||||
return <IBEXRender size={size}>
|
||||
<IBEXLogic
|
||||
initialState={initialState}
|
||||
size={size}
|
||||
tick={tick}
|
||||
forestGrowFactor={forestGrowFactor}
|
||||
waterFactor={waterFactor}
|
||||
fireFactor={fireFactor}
|
||||
/>
|
||||
</IBEXRender>;
|
||||
}
|
||||
});
|
||||
|
||||
// This should be implemented in a shader (it's a cellular automaton too)
|
||||
// but it's how it was done in the game
|
||||
function generate (startX: number, worldSize: [number,number]) {
|
||||
var worldPixelRawBuf = new Uint8Array(worldSize[0] * worldSize[1] * 4);
|
||||
var worldPixelBuf = new Uint8Array(worldSize[0] * worldSize[1]);
|
||||
var waterInGeneration = 0;
|
||||
var volcanoInGeneration = 0;
|
||||
var w = worldSize[0], h = worldSize[1];
|
||||
function step (a, b, x) {
|
||||
return Math.max(0, Math.min((x-a) / (b-a), 1));
|
||||
}
|
||||
function affectColor (buf, i, c) {
|
||||
buf[i] = ~~(256 * c / 9);
|
||||
buf[i+3] = 1;
|
||||
}
|
||||
function get (b, x, y) {
|
||||
if (x >= 0 && x < w && y >= 0 && y < h) {
|
||||
return b[x + y * w];
|
||||
}
|
||||
return y > 50 ? 1 : 0;
|
||||
}
|
||||
function set (b, x, y, e) {
|
||||
if (x >= 0 && x < w && y >= 0 && y < h) {
|
||||
b[x + y * w] = e;
|
||||
}
|
||||
}
|
||||
var K = 26;
|
||||
var x, y, i, k, e;
|
||||
for (x = startX; x < worldSize[0]; ++x) {
|
||||
for (y = 0; y < worldSize[1]; ++y) {
|
||||
e = +(Math.random() >
|
||||
0.22
|
||||
+ 0.3 * (step(0, 20, y)
|
||||
+ step(worldSize[1]-20, worldSize[1] - 2, y)));
|
||||
set(worldPixelBuf, x, y, e);
|
||||
}
|
||||
}
|
||||
var swp = new Uint8Array(worldPixelBuf);
|
||||
var cur = worldPixelBuf;
|
||||
for (k = 0; k < K; ++k) {
|
||||
for (x = startX; x < worldSize[0]; ++x) {
|
||||
for (y = 0; y < worldSize[1]; ++y) {
|
||||
var me = get(cur, x, y);
|
||||
var sum =
|
||||
0.1 * me +
|
||||
(0.9 + 0.1 * Math.random()) * (get(cur, x-1, y-1)?1:0) +
|
||||
(0.9 + 0.1 * Math.random()) * (get(cur, x, y-1)?1:0) +
|
||||
(0.9 + 0.1 * Math.random()) * (get(cur, x+1, y-1)?1:0) +
|
||||
(1.4 + 0.2 * Math.random()) * (get(cur, x-1, y)?1:0) +
|
||||
(1.1 + 0.2 * Math.random()) * (get(cur, x+1, y)?1:0) +
|
||||
(1.6 - 0.1 * Math.random()) * (get(cur, x-1, y+1)?1:0) +
|
||||
(1.2 - 0.2 * Math.random()) * (get(cur, x, y+1)?1:0) +
|
||||
(1.0 - 0.1 * Math.random()) * (get(cur, x+1, y+1?1:0));
|
||||
let e = +(sum <= 6 + (Math.random()-0.5) * (1-k/K));
|
||||
if (e && sum >= 6 - Math.random() * waterInGeneration + 4 * step(110, 0, y)) e = 5;
|
||||
if (e && sum >= 6 - Math.random() * volcanoInGeneration + 6 * step(20, 60, y)) e = 4;
|
||||
set(swp, x, y, e);
|
||||
}
|
||||
}
|
||||
var tmp = swp;
|
||||
swp = cur;
|
||||
cur = tmp;
|
||||
}
|
||||
if (swp === cur) worldPixelBuf = swp;
|
||||
for (i = 0; i < worldPixelBuf.length; ++i) {
|
||||
affectColor(worldPixelRawBuf, 4 * i, worldPixelBuf[i]);
|
||||
}
|
||||
return ndarray(worldPixelRawBuf, [ worldSize[0], worldSize[1], 4]).transpose(1, 0, 2).step(1, -1, 1);
|
||||
}
|
||||
|
||||
const size = [200,200];
|
||||
|
||||
export default class Example extends Component {
|
||||
state = {
|
||||
initialState: generate(0, size),
|
||||
};
|
||||
render() {
|
||||
const { forestGrowFactor, fireFactor, waterFactor, speed } = this.props;
|
||||
const { initialState } = this.state;
|
||||
return (
|
||||
<Surface width={400} height={400}>
|
||||
<Game
|
||||
speed={speed}
|
||||
size={size}
|
||||
initialState={initialState}
|
||||
forestGrowFactor={forestGrowFactor}
|
||||
fireFactor={fireFactor}
|
||||
waterFactor={waterFactor}
|
||||
/>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
speed: 60,
|
||||
forestGrowFactor: 1,
|
||||
fireFactor: 0,
|
||||
waterFactor: 0,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Game Rule Interactions.
|
||||
*
|
||||
* Each interaction use various probability. Some are very rare, some frequent.
|
||||
/!\ here air means wind /!\ it is different of empty, the empty space is
|
||||
* called "Nothing" aka N)
|
||||
*
|
||||
* Primary elements: Water, Fire, Earth, Air
|
||||
* =======
|
||||
* Water + Nothing => fall / slide
|
||||
* Fire + Nothing => grow
|
||||
* Air + Nothing => move (directional wind)
|
||||
* Water + Air => Water is deviated (wind)
|
||||
* Fire + Air => Fire decrease
|
||||
* Earth + Water => rarely creates Water Source (water infiltration)
|
||||
* Earth + Fire => rarely creates Volcano (fire melt ground into lava)
|
||||
*
|
||||
* Secondary elements: Source, Volcano
|
||||
* =========
|
||||
* Source + Nothing => creates Water (on bottom).
|
||||
* Volcano + Nothing => creates Fire (on top)
|
||||
* Volcano + Source => IF source on top of volcano: sometimes creates Ground.
|
||||
* OTHERWISE: sometimes creates volcano.
|
||||
* Volcano + Water => rarely creates Source.
|
||||
* Earth + Volcano => rarely Volcano expand / grow up in the Earth.
|
||||
* Earth + Source => rarely Source expand / infiltrate in the Earth.
|
||||
* Source + Fire => Source die.
|
||||
*
|
||||
* Cases where nothing happens:
|
||||
* Water + Fire
|
||||
* Earth + Nothing
|
||||
* Volcano + Fire
|
||||
* Volcano + Air
|
||||
* Earth + Air
|
||||
* Source + Air
|
||||
* Source + Water
|
||||
*/
|
||||
18
cookbook-rn/src/examples/ibex/meta.js
Normal file
@ -0,0 +1,18 @@
|
||||
import makeFloatSlider from "../../toolbox/makeFloatSlider";
|
||||
|
||||
export const title = "IBEX (js13k 2014 – greweb)";
|
||||
|
||||
export const toolbox = [
|
||||
{ prop: "speed",
|
||||
title: (value) => "Simulation Speed ("+value+" FPS)",
|
||||
Editor: makeFloatSlider(1, 60, 1) },
|
||||
{ prop: "forestGrowFactor",
|
||||
title: "Forest Grow Factor",
|
||||
Editor: makeFloatSlider(0, 50, 1) },
|
||||
{ prop: "waterFactor",
|
||||
title: "Water Factor",
|
||||
Editor: makeFloatSlider(0, 1, 0.01) },
|
||||
{ prop: "fireFactor",
|
||||
title: "Volcano Factor",
|
||||
Editor: makeFloatSlider(0, 1, 0.01) },
|
||||
];
|
||||
99
cookbook-rn/src/examples/index.js
Normal file
@ -0,0 +1,99 @@
|
||||
// This file is generated by `npm run generate-examples` from index.txt
|
||||
import hellogl_E from './hellogl';
|
||||
import * as hellogl_m from './hellogl/meta';
|
||||
export const hellogl={ Example: hellogl_E, ...hellogl_m };
|
||||
import helloblue_E from './helloblue';
|
||||
import * as helloblue_m from './helloblue/meta';
|
||||
export const helloblue={ Example: helloblue_E, ...helloblue_m };
|
||||
import helloblueanim_E from './helloblueanim';
|
||||
import * as helloblueanim_m from './helloblueanim/meta';
|
||||
export const helloblueanim={ Example: helloblueanim_E, ...helloblueanim_m };
|
||||
import colordisc_E from './colordisc';
|
||||
import * as colordisc_m from './colordisc/meta';
|
||||
export const colordisc={ Example: colordisc_E, ...colordisc_m };
|
||||
import gradients_E from './gradients';
|
||||
import * as gradients_m from './gradients/meta';
|
||||
export const gradients={ Example: gradients_E, ...gradients_m };
|
||||
import diamondcrop_E from './diamondcrop';
|
||||
import * as diamondcrop_m from './diamondcrop/meta';
|
||||
export const diamondcrop={ Example: diamondcrop_E, ...diamondcrop_m };
|
||||
import diamondhello_E from './diamondhello';
|
||||
import * as diamondhello_m from './diamondhello/meta';
|
||||
export const diamondhello={ Example: diamondhello_E, ...diamondhello_m };
|
||||
import diamondanim_E from './diamondanim';
|
||||
import * as diamondanim_m from './diamondanim/meta';
|
||||
export const diamondanim={ Example: diamondanim_E, ...diamondanim_m };
|
||||
import heart_E from './heart';
|
||||
import * as heart_m from './heart/meta';
|
||||
export const heart={ Example: heart_E, ...heart_m };
|
||||
import animated_E from './animated';
|
||||
import * as animated_m from './animated/meta';
|
||||
export const animated={ Example: animated_E, ...animated_m };
|
||||
import saturation_E from './saturation';
|
||||
import * as saturation_m from './saturation/meta';
|
||||
export const saturation={ Example: saturation_E, ...saturation_m };
|
||||
import colorscale_E from './colorscale';
|
||||
import * as colorscale_m from './colorscale/meta';
|
||||
export const colorscale={ Example: colorscale_E, ...colorscale_m };
|
||||
import distortion_E from './distortion';
|
||||
import * as distortion_m from './distortion/meta';
|
||||
export const distortion={ Example: distortion_E, ...distortion_m };
|
||||
import transitions_E from './transitions';
|
||||
import * as transitions_m from './transitions/meta';
|
||||
export const transitions={ Example: transitions_E, ...transitions_m };
|
||||
import glsledit_E from './glsledit';
|
||||
import * as glsledit_m from './glsledit/meta';
|
||||
export const glsledit={ Example: glsledit_E, ...glsledit_m };
|
||||
import paint_E from './paint';
|
||||
import * as paint_m from './paint/meta';
|
||||
export const paint={ Example: paint_E, ...paint_m };
|
||||
import pixeleditor_E from './pixeleditor';
|
||||
import * as pixeleditor_m from './pixeleditor/meta';
|
||||
export const pixeleditor={ Example: pixeleditor_E, ...pixeleditor_m };
|
||||
import blurxy_E from './blurxy';
|
||||
import * as blurxy_m from './blurxy/meta';
|
||||
export const blurxy={ Example: blurxy_E, ...blurxy_m };
|
||||
import blurxydownscale_E from './blurxydownscale';
|
||||
import * as blurxydownscale_m from './blurxydownscale/meta';
|
||||
export const blurxydownscale={ Example: blurxydownscale_E, ...blurxydownscale_m };
|
||||
import blurmulti_E from './blurmulti';
|
||||
import * as blurmulti_m from './blurmulti/meta';
|
||||
export const blurmulti={ Example: blurmulti_E, ...blurmulti_m };
|
||||
import blurmap_E from './blurmap';
|
||||
import * as blurmap_m from './blurmap/meta';
|
||||
export const blurmap={ Example: blurmap_E, ...blurmap_m };
|
||||
import blurmapmouse_E from './blurmapmouse';
|
||||
import * as blurmapmouse_m from './blurmapmouse/meta';
|
||||
export const blurmapmouse={ Example: blurmapmouse_E, ...blurmapmouse_m };
|
||||
import blurmapdyn_E from './blurmapdyn';
|
||||
import * as blurmapdyn_m from './blurmapdyn/meta';
|
||||
export const blurmapdyn={ Example: blurmapdyn_E, ...blurmapdyn_m };
|
||||
import * as blurimgtitle_m from './_TODO_blurimgtitle/meta';
|
||||
export const blurimgtitle={ Example: null, ...blurimgtitle_m };
|
||||
import gol_E from './gol';
|
||||
import * as gol_m from './gol/meta';
|
||||
export const gol={ Example: gol_E, ...gol_m };
|
||||
import golglider_E from './golglider';
|
||||
import * as golglider_m from './golglider/meta';
|
||||
export const golglider={ Example: golglider_E, ...golglider_m };
|
||||
import golrot_E from './golrot';
|
||||
import * as golrot_m from './golrot/meta';
|
||||
export const golrot={ Example: golrot_E, ...golrot_m };
|
||||
import golrotscu_E from './golrotscu';
|
||||
import * as golrotscu_m from './golrotscu/meta';
|
||||
export const golrotscu={ Example: golrotscu_E, ...golrotscu_m };
|
||||
import mergechannels_E from './mergechannels';
|
||||
import * as mergechannels_m from './mergechannels/meta';
|
||||
export const mergechannels={ Example: mergechannels_E, ...mergechannels_m };
|
||||
import demotunnel_E from './demotunnel';
|
||||
import * as demotunnel_m from './demotunnel/meta';
|
||||
export const demotunnel={ Example: demotunnel_E, ...demotunnel_m };
|
||||
import demodesert_E from './demodesert';
|
||||
import * as demodesert_m from './demodesert/meta';
|
||||
export const demodesert={ Example: demodesert_E, ...demodesert_m };
|
||||
import demodesertcrt_E from './demodesertcrt';
|
||||
import * as demodesertcrt_m from './demodesertcrt/meta';
|
||||
export const demodesertcrt={ Example: demodesertcrt_E, ...demodesertcrt_m };
|
||||
import ibex_E from './ibex';
|
||||
import * as ibex_m from './ibex/meta';
|
||||
export const ibex={ Example: ibex_E, ...ibex_m };
|
||||
33
cookbook-rn/src/examples/index.txt
Normal file
@ -0,0 +1,33 @@
|
||||
hellogl
|
||||
helloblue
|
||||
helloblueanim
|
||||
colordisc
|
||||
gradients
|
||||
diamondcrop
|
||||
diamondhello
|
||||
diamondanim
|
||||
heart
|
||||
animated
|
||||
saturation
|
||||
colorscale
|
||||
distortion
|
||||
transitions
|
||||
glsledit
|
||||
paint
|
||||
pixeleditor
|
||||
blurxy
|
||||
blurxydownscale
|
||||
blurmulti
|
||||
blurmap
|
||||
blurmapmouse
|
||||
blurmapdyn
|
||||
blurimgtitle
|
||||
gol
|
||||
golglider
|
||||
golrot
|
||||
golrotscu
|
||||
mergechannels
|
||||
demotunnel
|
||||
demodesert
|
||||
demodesertcrt
|
||||
ibex
|
||||
BIN
cookbook-rn/src/examples/mergechannels/img1.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
cookbook-rn/src/examples/mergechannels/img2.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
cookbook-rn/src/examples/mergechannels/img3.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
cookbook-rn/src/examples/mergechannels/img4.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
cookbook-rn/src/examples/mergechannels/img5.png
Normal file
|
After Width: | Height: | Size: 183 KiB |
BIN
cookbook-rn/src/examples/mergechannels/img6.png
Normal file
|
After Width: | Height: | Size: 177 KiB |
BIN
cookbook-rn/src/examples/mergechannels/img7.png
Normal file
|
After Width: | Height: | Size: 202 KiB |