three.js textureloader multiple images - javascript

So I have a website that does a few things in webgl w/ three.js, and I noticed that loadTexture is going away soon, and that I should probably switch to using textureloaders. Basically, i'd like to preload all my textures before any code executes at the start of my code. I was thinking about doing something like below, which will allow me to load any number of images, and assign them to a texture object that can be called when needed.
var loadedtex = {}
var to_load = ['images/a.png','images/b.png','images/c.png']
var texture_loader = new THREE.TextureLoader();
for(var i=0;i<to_load.length;i++){
texture_loader.load(to_load[i],function(tex){
loadedtex[to_load[i]] = tex
})
}
I'm probably missing something obvious, but I can't quite get it to work correctly. When I use the code above, loadedtex will fill up loadedtex['images/c.png'] every time, instead of properly looping and remember which "i" value it should be using.
Proper result should be something like:
loadedtex['images/a.png'] = Three.Texture{}...
loadedtex['images/b.png'] = Three.Texture{}...
loadedtex['images/c.png'] = Three.Texture{}...
but what i really get is:
loadedtex['images/c.png'] = Three.Texture{}
I know its because the "i" variable will always be max value by the time anything loads, but i'm not sure how to accomplish what i want.
Thanks.
---edit---
This is what I ended up with. Seems to work well. Thanks for the advice.
var loadedtex = {}
var textureloaded = 0
var to_load = ['images/a.png','images/b.png','images/c.png']
var texture_loader = new THREE.TextureLoader();
load_textures = function(){
if (textureloaded == to_load.length){return}
var texture = to_load[textureloaded]
texture_loader.load(texture,function(tex){
loadedtex[texture] = tex
textureloaded += 1
load_textures()
})
}
load_textures()

If you're using ES6:
let assets = [
{ name:'img1', url:'img/img1.png' },
{ name:'img2', url:'img/img2.png' },
{ name:'img3', url:'img/img3.png' },
];
this.textures = {};
for ( let img of assets ) {
this.loader.load(img.url, ( texture ) => {
this.textures[img.name] = texture;
assets.splice( assets.indexOf(img), 1);
if ( !assets.length ) {
this.init()
}
console.log('[TextureLoader] Loaded %o', img.name);
});
}

Try to make a closure function for it like,
for(var i=0;i<to_load.length;i++){
(function(tl){
texture_loader.load(tl,function(tex){
loadedtex[tl] = tex
})
})(to_load[i]);
}

Related

Why does every other object I create in a loop turns out blank on old version of Chrome?

It's something that's really bothering me, and it's also kind of important since it's part of my job.
I made an object that basically parses a hostname and puts labels on the different parts of that name.
Sounds pretty straightforward, right? HOWEVER, when I create several instances of that object in a row, every other instance turns out blank, with nothing but _proto and a few functions. No data whatsoever.
It might be important to note that I'm using an old version of Chrome (which I have to use, since the network at work is closed-circuit and it's impossible to update the software beyond what's on the net). The same code works at home.
WHAT AM I DOING WRONG, THEN?
Thanks in advance.
var reg = /([A,B,C,D,E])(\d{3})(\d{2})([F,G,H])(\d{2})/i;
var hostParser = function(hostname) {
var parsed = reg.exec(hostname);
if (parsed) {
this.prefix = parsed[1];
this.arena = parsed[2];
this.waitingRoom = parsed[3];
this.adminStatus = parsed[4];
this.ID = parsed[5];
this.hostname = hostname.toUpperCase();
return this;
}
return false;
};
Array.prototype.eliminateDuplicates = function() {
var r = [];
this.forEach(function(n) {
if (r.indexOf(n) < 0)
r.push(n);
});
return r;
};
Array.prototype.trim = function() {
var r = [];
this.forEach(function (n) {
if (!/^\s?$/.test(n))
r.push(n);
});
return r;
};
var list = [
'A40800G01',
'A40800G02',
'A40800G03',
'A40800G04',
'A40800G05',
'A40800G06',
'A40800G07',
'A40800G08',
'A40800G09'
];
list.trim().eliminateDuplicates().forEach(function (item) {
var itemParser = new hostParser(item);
console.log(itemParser);
});
This was indeed a bug with that particular Chrome version. Not being able to update, I duplicated array items on purpose and it worked.

How to add a set values for key to Javascript objects?

I have following javascript variable:
this.Edges = {};
Then I did
this.Edges[path] = {edgeDst};
So Edges variable at this point is somehing like
Edges['232kb32i23'] = { edgeDst: 'AND_m_5' }
after that I when I did
this.Edges[path] = {edgeSrc};
It overwrote the value I had added with edgeDst.
At this point Edges is like following:
Edges['232kb32i23'] = { edgeSrc: 'B_m_5' }
But I want to produce something like:
Edges['232kb32i23'] = { edgeDst: 'AND_m_5', edgeSrc: 'B_m_5' }
Here I can't added edgeSrc and edgeDst simulataneously.
How will I achieve this?
You can use the following:
var Edges = {}; // these are just so that you can run the snippet
var path = '232kb32i23';
Edges[path] = {}; // set Edges[path] to a new object
Edges[path].edgeDst = 'AND_m_5'; // set the edgeDst property on Edges[path]
Edges[path].edgeSrc = 'B_m_5'; // set the edgeSrc property on Edges[path]
console.log(Edges); // run the snippet to see the result
console.log(Edges['232kb32i23']);
You will have to modify the code to use this for your application, but I tried to make as succinct an example as possible.
If you want to use the new ES6 syntactic sugar. It looks like you can do something like this:
this.Edges = {};
var path = 'the_path',
edgeDst = 'edgeDst',
edgeSrc = 'edgeSrc';
this.Edges[path] = { edgeDst, edgeSrc };
console.log(this.Edges) => {edgeDs:"AND_m_5",edgeSrc:"edgeSrc"}
Here is a link to a functioning example: https://jsfiddle.net/xwf3wadr/

Get WebGL texture/buffer/shader count

Is there a way to get the count of the currently existing textures, buffers or shaders of a WebGL context? Like the numbers you can get in Firefox if you look at about:memory.
I'd like to check if all these are deleted successfully when my application closes.
There is no way to get that info directly from the WebGLRenderingContext but you could easily augment the context yourself something like
var numTextures = 0;
var originalCreateTextureFn = gl.createTexture;
var originalDeleteTextureFn = gl.deleteTexture;
gl.createTexture = function() {
++numTextures;
return originalCreateTextureFn.call(gl);
};
gl.deleteTexture = function(texture) {
--numTextures;
originalDeleteTextureFn.call(gl, texture);
};
You can write similar functions for other resources.
Of course if you want to be perfect you'd probably need to add a flag to each object just incase you try to delete something twice and also check the object passed in is actually the right kind. Something like
var numTextures = 0;
var originalCreateTextureFn = gl.createTexture;
var originalDeleteTextureFn = gl.deleteTexture;
gl.createTexture = function() {
++numTextures;
var texture = originalCreateTextureFn.call(gl);
texture.__deleted__ = false;
};
gl.deleteTexture = function(texture) {
if (texture && texture instanceof WebGLTexture && !texture.__deleted__) {
texture.__deleted__ = true;
--numTextures;
}
originalDeleteTextureFn.call(gl, texture);
};

Javascript array is undefined... and I'm not sure why

I'm trying to translate a PHP class into JavaScript. The only thing I'm having trouble with is getting an item out of an array variable. I've created a simple jsfiddle here. I cannot figure out why it won't work.
(EDIT: I updated this code to better reflect what I'm doing. Sorry for the previous mistake.)
function tattooEightBall() {
this.subjects = ['a bear', 'a tiger', 'a sailor'];
this.prediction = make_prediction();
var that = this;
function array_random_pick(somearray) {
//return array[array_rand(array)];
var length = somearray.length;
var random = somearray[Math.floor(Math.random()*somearray.length)];
return random;
}
function make_prediction() {
var prediction = array_random_pick(this.subjects);
return prediction;
}
}
var test = tattooEightBall();
document.write(test.prediction);
​
Works fine here, you are simple not calling
classname();
After you define the function.
Update
When you make a call to *make_prediction* , this will not be in scope. You are right on the money creating a that variable, use it on *make_prediction* :
var that = this;
this.prediction = make_prediction();
function make_prediction() {
var prediction = ''; //initialize it
prediction = prediction + array_random_pick(that.subjects);
return prediction;
}
You can see a working version here: http://jsfiddle.net/zKcpC/
This is actually pretty complex and I believe someone with more experience in Javascript may be able to clarify the situation.
Edit2: Douglas Crockfords explains it with these words:
By convention, we make a private that variable. This is used to make
the object available to the private methods. This is a workaround for
an error in the ECMAScript Language Specification which causes this to
be set incorrectly for inner functions.
To see the complete article head to: http://javascript.crockford.com/private.html
You never call classname. Seems to be working fine.
Works for me:
(function classname() {
this.list = [];
this.list[0] = "tiger";
this.list[1] = "lion";
this.list[2] = "bear";
function pickone(somearray) {
var length = somearray.length;
var random = somearray[Math.floor(Math.random()*length)];
return random;
}
var random_item = pickone(this.list);
document.write(random_item);
}());
Were you actually calling the classname function? Note I wrapped your code block in:
([your_code]());
I'm not sure what you're trying to accomplish exactly with the class structure you were using so I made some guesses, but this code works by creating a classname object that has instance data and a pickone method:
function classname() {
this.list = [];
this.list[0] = "tiger";
this.list[1] = "lion";
this.list[2] = "bear";
this.pickone = function() {
var length = this.list.length;
var random = this.list[Math.floor(Math.random()*length)];
return random;
}
}
var cls = new classname();
var random = cls.pickone();
You can play with it interactively here: http://jsfiddle.net/jfriend00/ReL2h/.
It's working fine for me: http://jsfiddle.net/YznSE/6/ You just didn't call classname(). If you don't call it, nothing will happen ;)
Make it into a self-executing function like this:
(function classname() {
this.list = [];
this.list[0] = "tiger";
this.list[1] = "lion";
this.list[2] = "bear";
function pickone(somearray) {
var length = somearray.length; //<---WHY ISN'T THIS DEFINED??
var random = somearray[Math.floor(Math.random() * length)];
return random;
}
var random_item = pickone(this.list);
document.write(random_item);
})();
var test = tattooEightBall();
document.write(test.prediction);
Should be:
var test = new tattooEightBall(); //forgot new keyword to create object
document.write(test.prediction()); // forgot parens to fire method
and:
this.prediction = make_prediction();
Should be:
this.prediction = make_prediction;

JavaScript new objects inside objects duplicating

I'm taking an adventure into the depths of JavaScript and have come across a little problem that I can't get my head around.
Everything I know about programming is self taught, this problem might have some terminology behind it I have never heard of, so I don't know what it would be called.
I'll explain the problem I am experiencing.
I've been writing a framework for HTML5 canvas for displaying 2d and 3d graphics.
As you might expect, I have designed an element class, these elements have positions on the canvas which are built from a vector class I put together.
The problem I'm having is, if I make two "Text" objects, then call a function inside their position object, all the positions of the "Text" objects change to this value:
var usernameLabel = new C.Text('Username:');
usernameLabel.position.set(30,30)
var username = new C.Text('Hello World');
username.position.set(0,70)
console.log(usernameLabel.position.x) // 0 when it should be 30
I'm sure there is something I missed, I just can't figure out what.
C.Text.prototype = new C.Element();
C.Element.position = new JC.Vector();
Any help would be most appreciated!
This is my full Element class
C.elements = 0;
C.Element = function()
{
this.id = C.elements ++;
this.position = new C.Vector();
this.rotation = new C.Vector();
this.style = new C.Style();
this.children = [];
}
C.Element.prototype = {
constructor : C.Element,
addChildObject : function( o )
{
return this.children.push(o);
},
removeChildObject : function( o )
{
this.children.splice(o,1);
}
}
Text class
C.Text = function(string)
{
this.string = string || '';
}
C.Text.prototype = new C.Element();
C.Text.prototype.constructor = C.Text();
I also have more classes built from C.Element obviously, for example:
C.Rectangle = function(width, height)
{
this.style.setSize(width,height);
}
C.Rectangle.prototype = new C.Element();
C.Rectangle.prototype.constructor = new C.Rectangle();
var usernameLabel = new C.Text('Username:');
usernameLabel.position.set(30,30) // 0,70?
var username = new C.Text('');
username.position.set(0,70) // 0,70
var rect = new C.Rectangle(20,0);
rect.position.set(30,80) // 90,80?
var rect2 = new C.Rectangle(20,0);
rect2.position.set(90,80) // 90,80
From the looks of it, you are declaring position as a 'static' variable on the object, which means it will change. To make it change only on a specific object you need one of the following:
C.Element.prototype.position = new JC.Vector();
or inside a function within the object
this.position = new JC.Vector();
These declarations are for items that are specific to the object, where as the C.Element.position declaration is for something that will be the same in all instances of the object.
Update
Instead of declaring C.Text.prototype = new C.Element(). Try using C.Text.prototype = C.Element.prototype. Hopefully that will fix your problem. Instead of creating a new object to base it on, it bases it directly on the prototype of C.Element
I found the answer! Thanks for the help! The solution was to make the parent object do a call
for a reason I don't fully understand.
C.Text = function(string)
{
C.Object.call(this)
this.string = string || '';
return this;
}
C.Text.prototype = new C.Object();
C.Text.prototype.constructor = C.Text;

Categories