Skip to content

Instantly share code, notes, and snippets.

@kefavn
Last active July 26, 2022 16:56
Show Gist options
  • Save kefavn/8e2ea1fa3fef4e2efaeaf10c30c75eed to your computer and use it in GitHub Desktop.
Save kefavn/8e2ea1fa3fef4e2efaeaf10c30c75eed to your computer and use it in GitHub Desktop.
Texture Generator
import Ember from 'ember';
import Game from 'app/three/game';
export default Ember.Component.extend({
didInsertElement() {
const three = new Game(this.$());
this.set('three', three);
three.start();
}
});
import Ember from 'ember';
export default Ember.Component.extend({
didReceiveAttrs() {
const canvas = this.get('textureCanvas');
if (this.$()) {
this.$().empty();
this.$().append(canvas);
}
},
});
import Ember from 'ember';
import TextureGenerator from 'app/texgen/texgen';
const { TG: TexGen } = window;
const { computed } = Ember;
export default Ember.Component.extend({
didReceiveAttrs() {
this._super(...arguments);
this._newContext();
if (this.$()) {
this.updateCanvas();
}
},
_newContext() {
const width = this.get('width');
const height = this.get('height');
const config = {
width,
height
};
this.set('texGenContext', new TextureGenerator(config));
},
didInsertElement() {
this._super(...arguments);
this.updateCanvas();
},
opOptions: computed(function() {
const keys = Object.keys(TG.OP);
return keys.sort();
}),
filterOptions: computed(function () {
const keys = Object.keys(TG);
return keys.filter((key) => (key != 'OP' && key != 'Texture' && key != 'Program'));
}),
updateCanvas() {
const texture = this.get('texGenContext.texture');
this.set('textureCanvas', texture.toCanvas());
},
actions: {
addProgram() {
const obj = Ember.Object.create({ programParams: [] });
this.get('textureState.programs').pushObject(obj);
},
addProgramParam(program, filter) {
filter = filter || this.get('filterOptions.firstObject');
const filterObject = new TexGen[filter]();
const filterObjectKeys = Object.keys(filterObject).filter(value => !value.includes('get'));
const obj = Ember.Object.create({ paramKeys: filterObjectKeys, paramValue: [] });
program.get('programParams').pushObject(obj);
},
updateProgramParam(param, value) {
param.set('paramKey', value);
param.set('paramValue', Ember.Object.create({0: 0}));
if (value == 'tint') {
param.set('paramValue', Ember.Object.create({0: 0, 1: 0, 2: 0}));
}
},
updateProgramParamValue(paramValue, key, value) {
paramValue.set(key, Number(value));
},
removeProgram(program, programList) {
programList.removeObject(program);
},
generate() {
const texGenContext = this.get('texGenContext');
let chainedTexture = texGenContext.texture;
this.get('textureState.programs').forEach(program => {
const operation = chainedTexture[program.operation.toLowerCase()];
let chainedProgram = new TexGen[program.filter]();
program.get('programParams').forEach((programParam) => {
const programFunction = chainedProgram[programParam.paramKey];
const programValues = Object.values(programParam.paramValue);
chainedProgram = programFunction.apply(chainedProgram, programValues);
});
chainedTexture = operation.apply(chainedTexture, [chainedProgram]);
});
texGenContext.texture = chainedTexture;
this.updateCanvas();
this._newContext();
}
}
});
import { degreesToRadians } from 'app/utils';
export const HEIGHT = 800;
export const WIDTH = 800;
export const COLOR_WHITE = 0xffffff;
export const COLOR_FOG = COLOR_WHITE;
export const COLOR_BACKGROUND = 0x2A5263;
export const FOG_EXPONENT = 0.03;
export const OPACITY_FULL = 1;
export const OPACITY_BACKGROUND = OPACITY_FULL;
export const SCENE_HEIGHT = 800;
export const SCENE_WIDTH = 800;
export const SCENE_HEIGHT_WIDTH_RATIO = SCENE_WIDTH / SCENE_HEIGHT;
export const CAMERA_FOV = 30;
export const CAMERA_RENDER_NEAR_PLANE = 1;
export const CAMERA_RENDER_FAR_PLANE = 1000;
export const RENDERER_ANTIALIAS = false;
export const CAMERA_ISOMETRIC_ROTATION = degreesToRadians(50);
const { Stats: WindowStats, THREE: WindowThree } = window;
export const Sts = WindowStats;
export const Thr = WindowThree;
import Ember from 'ember';
const defaults = {
TEXTURE_WIDTH: 256,
TEXTURE_HEIGHT: 256
};
const { computed } = Ember;
export default Ember.Controller.extend({
queryParams: ['textureStateString', 'meow'],
meow: 1,
textureState: {
programs: [],
width: defaults.TEXTURE_WIDTH,
height: defaults.TEXTURE_HEIGHT
},
textureStateString: computed('textureState.programs.[]', 'textureState.width', 'textureState.height', function() {
const string = JSON.stringify(this.get('textureState'));
console.log(string);
this.incrementProperty('meow');
return this.get('textureState.width');
}),
actions: {
update(key, value) {
this.set(key, value);
}
}
});
import Ember from 'ember';
export function eq(params/*, hash*/) {
return params[0] == params[1];
}
export default Ember.Helper.helper(eq);
import Ember from 'ember';
import config from './config/environment';
const Router = Ember.Router.extend({
location: 'none',
rootURL: config.rootURL
});
Router.map(function() {
Router.map(function() {
this.route('texture', function() {});
});
});
export default Router;
import Ember from 'ember';
export default Ember.Route.extend({
beforeModel() {
this.transitionTo('texture');
},
});
html {
margin: 0;
width: 100%;
height: 100%;
}
body {
margin: 0;
width: 100%;
height: 100%;
color: #B2B6BD;
background-color: #2b303b;
}
div {
padding: 8px;
}
.form-field--label {
display: none;
}
.row .button {
color: #B2B6BD;
}
.row .button-primary {
color: #333;
}
.scroll-table {
width: 100%;
max-height: 100%;
}
.scroll-row {
overflow-y: scroll;
}
select.blank-state {
/*
background-color: #c96e60;
*/
}
<table class="scroll-table">
<tr>
{{one-way-input
value=width
update=(action update 'textureState.width')
}}
<span style="margin-left: 10px; margin-right: 10px">By </span>
{{one-way-input
value=height
update=(action update 'textureState.height')
}}
</tr>
<tr>
{{texture-component
textureCanvas=textureCanvas
classNames="stick-top"
}}
</tr>
<tr class="scroll-row">
{{#each textureState.programs as |program|}}
<div style="border: 1px solid; border-radius: 5px; margin-bottom: 8px;">
<div class="row">
{{one-way-select
value=program.operation
prompt="Operation"
options=opOptions
classNames=(if program.operation "four columns" "four columns blank-state")
update=(action (mut program.operation))
}}
{{one-way-select
value=program.filter
prompt="Program"
options=filterOptions
classNames=(if program.filter "six columns" "six columns blank-state")
update=(action (mut program.filter))
}}
<div class="button" {{action 'removeProgram' program textureState.programs }}>
Remove
</div>
</div>
<div>
{{#each program.programParams as |programParam|}}
<div class="row" style="border: 1px solid; border-radius: 5px; margin-bottom: 8px;">
{{one-way-select
value=programParam.paramKey
prompt="Param"
options=programParam.paramKeys
classNames=(if programParam.paramKey "three columns" "three columns blank-state")
update=(action 'updateProgramParam' programParam)
}}
<div class="button" {{action 'removeProgram' programParam program.programParams }}>
Remove
</div>
<div class="seven columns">
{{#each-in programParam.paramValue as |key paramValue|}}
{{#if (eq programParam.paramKey 'density')}}
{{one-way-input
value=paramValue
update=(action 'updateProgramParamValue' programParam.paramValue key)
}}
{{else}}
{{one-way-range
value=paramValue
max=1.0
min=0.0
step=0.001
update=(action 'updateProgramParamValue' programParam.paramValue key)
}}
{{/if}}
{{/each-in}}
</div>
</div>
{{/each}}
</div>
<div class="row">
<div
class="twelve columns button button"
{{action 'addProgramParam' program program.filter}}
>
Add Program Param
</div>
</div>
</div>
{{/each}}
<div class="row">
<div class="twelve columns button" {{action 'addProgram'}}>
Add Program
</div>
</div>
<div class="row">
<div class="twelve columns button button-primary" {{action 'generate'}}>
Generate
</div>
</div>
</tr>
</table>
<article class="container" style="text-align:center">
<h4>Texture Generator</h4>
{{texture-modify-component
textureState=textureState
width=textureState.width
height=textureState.height
update=(action 'update')
}}
</article>
const { TG: TexGen } = window;
export default class TextureGenerator {
constructor(config) {
this.texture = new TG.Texture( config.width, config.height );
}
}
import {
COLOR_FOG,
FOG_EXPONENT,
CAMERA_FOV,
SCENE_HEIGHT_WIDTH_RATIO,
CAMERA_RENDER_NEAR_PLANE,
CAMERA_RENDER_FAR_PLANE,
CAMERA_ISOMETRIC_ROTATION,
RENDERER_ANTIALIAS,
COLOR_BACKGROUND,
OPACITY_BACKGROUND,
SCENE_HEIGHT,
SCENE_WIDTH
} from 'app/constants';
import {
Thr,
Sts
} from 'app/constants';
export default class statsSetup {
constructor() {
const stats = new Sts();
const element = stats.domElement;
element.style.position = 'relative';
element.style.top = '0px';
Object.assign(this, {
stats,
element
});
}
};
import {
COLOR_FOG,
FOG_EXPONENT,
CAMERA_FOV,
SCENE_HEIGHT_WIDTH_RATIO,
CAMERA_RENDER_NEAR_PLANE,
CAMERA_RENDER_FAR_PLANE,
CAMERA_ISOMETRIC_ROTATION,
RENDERER_ANTIALIAS,
COLOR_BACKGROUND,
OPACITY_BACKGROUND,
SCENE_HEIGHT,
SCENE_WIDTH
} from 'app/constants';
import {
Thr,
Sts
} from 'app/constants';
export default class ThreeContext {
constructor() {
const fog = new Thr.FogExp2(COLOR_FOG, FOG_EXPONENT);
const scene = new Thr.Scene();
scene.fog = fog;
const camera = new Thr.PerspectiveCamera(CAMERA_FOV, SCENE_HEIGHT_WIDTH_RATIO, CAMERA_RENDER_NEAR_PLANE, CAMERA_RENDER_FAR_PLANE);
camera.position.set(6, -6, 8);
camera.rotation.set(CAMERA_ISOMETRIC_ROTATION, 0, 0);
const renderer = new Thr.WebGLRenderer({ antialias: RENDERER_ANTIALIAS });
renderer.setClearColor(COLOR_BACKGROUND, OPACITY_BACKGROUND);
renderer.setSize(SCENE_HEIGHT, SCENE_WIDTH);
const element = renderer.domElement;
Object.assign(this, {
scene,
camera,
renderer,
element
});
}
render() {
return this.renderer.render(this.scene, this.camera);
}
};
import ThreeContext from 'app/three/contexts/three';
import StatsContext from 'app/three/contexts/stats';
export default class Game {
constructor(canvasElement) {
const setups = new Map([
['three', new ThreeContext()],
['stats', new StatsContext()]
]);
setups.forEach((value, key, map) => {
this[key + 'Context'] = value;
if (value.element) {
canvasElement.append(value.element);
}
});
}
start() {
this._animate();
}
// Private
_render() {
this.threeContext.render();
};
_animate() {
requestAnimationFrame(() => {
this._animate();
});
this._render();
this.statsContext.stats.update();
}
}
{
"version": "0.11.0",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "2.10.2",
"ember-data": "2.11.0",
"ember-template-compiler": "2.10.2",
"ember-testing": "2.10.2",
"skeleton-css": "https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css",
"three-js": "http://threejs.org/build/three.min.js",
"texgen": "https://cdn.rawgit.com/mrdoob/texgen.js/master/src/TexGen.js",
"doob-stats": "https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.js"
},
"addons": {
"ember-composable-helpers": "2.0.0",
"ember-one-way-controls": "2.0.0"
}
}
export function degreesToRadians(degrees) {
return degrees * Math.PI / 180.0;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment