Skip to content

Commit

Permalink
Add crunch support to imagery provider and material. Add loadCRN test…
Browse files Browse the repository at this point in the history
…s. Update CHANGES.md.
  • Loading branch information
bagnell committed Jan 5, 2017
1 parent 5875390 commit ee6856c
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 15 deletions.
3 changes: 2 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ Change Log
### TODO

* Added compressed texture support.
* glTF models and imagery layers can now reference [KTX](https://www.khronos.org/opengles/sdk/tools/KTX/) textures.
* glTF models and imagery layers can now reference [KTX](https://www.khronos.org/opengles/sdk/tools/KTX/) textures and textures compressed with [crunch](https://github.com/BinomialLLC/crunch).
* Added `loadKTX` to load KTX textures.
* Added `loadCRN` to load crunch compressed textures.
* Added new `PixelFormat` and `WebGLConstants` enums from WebGL extensions `WEBGL_compressed_s3tc`, `WEBGL_compressed_texture_pvrtc`, and `WEBGL_compressed_texture_etc1`. [#4758](https://github.com/AnalyticalGraphicsInc/cesium/pull/4758)

### 1.30 - 2017-02-01
Expand Down
7 changes: 6 additions & 1 deletion Source/Scene/ImageryProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ define([
'../Core/defined',
'../Core/defineProperties',
'../Core/DeveloperError',
'../Core/loadCRN',
'../Core/loadImage',
'../Core/loadImageViaBlob',
'../Core/loadKTX',
Expand All @@ -11,6 +12,7 @@ define([
defined,
defineProperties,
DeveloperError,
loadCRN,
loadImage,
loadImageViaBlob,
loadKTX,
Expand Down Expand Up @@ -296,7 +298,8 @@ define([
*/
ImageryProvider.prototype.pickFeatures = DeveloperError.throwInstantiationError;

var ktxRegex = /(^data:image\/ktx)|(\.ktx$)/i;
var ktxRegex = /\.ktx$/i;
var crnRegex = /\.crn$/i;

/**
* Loads an image from a given URL. If the server referenced by the URL already has
Expand All @@ -312,6 +315,8 @@ define([
ImageryProvider.loadImage = function(imageryProvider, url) {
if (ktxRegex.test(url)) {
return throttleRequestByServer(url, loadKTX);
} else if (crnRegex.test(url)) {
return throttleRequestByServer(url, loadCRN);
} else if (defined(imageryProvider.tileDiscardPolicy)) {
return throttleRequestByServer(url, loadImageViaBlob);
}
Expand Down
26 changes: 14 additions & 12 deletions Source/Scene/Material.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ define([
'../Core/destroyObject',
'../Core/DeveloperError',
'../Core/isArray',
'../Core/loadCRN',
'../Core/loadImage',
'../Core/loadKTX',
'../Core/Matrix2',
Expand Down Expand Up @@ -43,6 +44,7 @@ define([
destroyObject,
DeveloperError,
isArray,
loadCRN,
loadImage,
loadKTX,
Matrix2,
Expand Down Expand Up @@ -679,6 +681,7 @@ define([
};

var ktxRegex = /\.ktx$/i;
var crnRegex = /\.crn$/i;

function createTexture2DUpdateFunction(uniformId) {
var oldUniformValue;
Expand Down Expand Up @@ -758,21 +761,20 @@ define([

if (uniformValue !== material._texturePaths[uniformId]) {
if (typeof uniformValue === 'string') {
var promise;
if (ktxRegex.test(uniformValue)) {
when(loadKTX(uniformValue), function(image) {
material._loadedImages.push({
id : uniformId,
image : image
});
});
promise = loadKTX(uniformValue);
} else if (crnRegex.test(uniformValue)) {
promise = loadCRN(uniformValue);
} else {
when(loadImage(uniformValue), function(image) {
material._loadedImages.push({
id : uniformId,
image : image
});
});
promise = loadImage(uniformValue);
}
when(promise, function(image) {
material._loadedImages.push({
id : uniformId,
image : image
});
});
} else if (uniformValue instanceof HTMLCanvasElement) {
material._loadedImages.push({
id : uniformId,
Expand Down
150 changes: 150 additions & 0 deletions Specs/Core/loadCRNSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*global defineSuite*/
defineSuite([
'Core/loadCRN',
'Core/PixelFormat',
'Core/RequestErrorEvent',
'Core/RuntimeError'
], function(
loadCRN,
PixelFormat,
RequestErrorEvent,
RuntimeError) {
'use strict';

var validCompressed = new Uint8Array([72, 120, 0, 74, 227, 123, 0, 0, 0, 138, 92, 167, 0, 4, 0, 4, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 22, 0, 1, 0, 0, 96, 0, 0, 12, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 108, 0, 0, 0, 137, 0, 10, 96, 0, 0, 0, 0, 0, 0, 16, 4, 9, 130, 0, 0, 0, 0, 0, 0, 109, 4, 0, 0, 198, 96, 128, 0, 0, 0, 0, 0, 26, 80, 0, 0, 6, 96, 0, 0, 0, 0, 0, 0, 16, 0, 51, 0, 0, 0, 0, 0, 0, 0, 128, 1, 152, 0, 0, 0, 0, 0, 0, 4, 0]);
var fakeXHR;

beforeEach(function() {
fakeXHR = jasmine.createSpyObj('XMLHttpRequest', ['send', 'open', 'setRequestHeader', 'abort', 'getAllResponseHeaders']);
fakeXHR.simulateLoad = function(response) {
fakeXHR.status = 200;
fakeXHR.response = response;
if (typeof fakeXHR.onload === 'function') {
fakeXHR.onload();
}
};
fakeXHR.simulateError = function() {
fakeXHR.response = '';
if (typeof fakeXHR.onerror === 'function') {
fakeXHR.onerror();
}
};
fakeXHR.simulateHttpError = function(statusCode, response) {
fakeXHR.status = statusCode;
fakeXHR.response = response;
if (typeof fakeXHR.onload === 'function') {
fakeXHR.onload();
}
};

spyOn(window, 'XMLHttpRequest').and.returnValue(fakeXHR);
});

it('throws with no url', function() {
expect(function() {
loadCRN();
}).toThrowDeveloperError();
});

it('creates and sends request without any custom headers', function() {
var testUrl = 'http://example.invalid/testuri';
loadCRN(testUrl);

expect(fakeXHR.open).toHaveBeenCalledWith('GET', testUrl, true);
expect(fakeXHR.setRequestHeader).not.toHaveBeenCalled();
expect(fakeXHR.send).toHaveBeenCalled();
});

it('creates and sends request with custom headers', function() {
var testUrl = 'http://example.invalid/testuri';
loadCRN(testUrl, {
'Accept' : 'application/json',
'Cache-Control' : 'no-cache'
});

expect(fakeXHR.open).toHaveBeenCalledWith('GET', testUrl, true);
expect(fakeXHR.setRequestHeader.calls.count()).toEqual(2);
expect(fakeXHR.setRequestHeader).toHaveBeenCalledWith('Accept', 'application/json');
expect(fakeXHR.setRequestHeader).toHaveBeenCalledWith('Cache-Control', 'no-cache');
expect(fakeXHR.send).toHaveBeenCalled();
});

it('returns a promise that rejects when the request errors', function() {
var testUrl = 'http://example.invalid/testuri';
var promise = loadCRN(testUrl);

expect(promise).toBeDefined();

var resolvedValue;
var rejectedError;
promise.then(function(value) {
resolvedValue = value;
}, function(error) {
rejectedError = error;
});

expect(resolvedValue).toBeUndefined();
expect(rejectedError).toBeUndefined();

fakeXHR.simulateError();
expect(resolvedValue).toBeUndefined();
expect(rejectedError instanceof RequestErrorEvent).toBe(true);
expect(rejectedError.statusCode).toBeUndefined();
expect(rejectedError.response).toBeUndefined();
});

it('returns a promise that rejects when the request results in an HTTP error code', function() {
var testUrl = 'http://example.invalid/testuri';
var promise = loadCRN(testUrl);

expect(promise).toBeDefined();

var resolvedValue;
var rejectedError;
promise.then(function(value) {
resolvedValue = value;
}, function(error) {
rejectedError = error;
});

expect(resolvedValue).toBeUndefined();
expect(rejectedError).toBeUndefined();

var error = 'some error';
fakeXHR.simulateHttpError(404, error);
expect(resolvedValue).toBeUndefined();
expect(rejectedError instanceof RequestErrorEvent).toBe(true);
expect(rejectedError.statusCode).toEqual(404);
expect(rejectedError.response).toEqual(error);
});

it('returns a promise that resolves to an compressed texture when the request loads', function() {
var testUrl = 'http://example.invalid/testuri';
var promise = loadCRN(testUrl);

expect(promise).toBeDefined();

var resolvedValue;
var rejectedError;
var newPromise = promise.then(function(value) {
resolvedValue = value;
}, function(error) {
rejectedError = error;
});

expect(resolvedValue).toBeUndefined();
expect(rejectedError).toBeUndefined();

var response = validCompressed.buffer;
fakeXHR.simulateLoad(response);

return newPromise.then(function() {
expect(resolvedValue).toBeDefined();
expect(resolvedValue.width).toEqual(4);
expect(resolvedValue.height).toEqual(4);
expect(PixelFormat.isCompressedFormat(resolvedValue.internalFormat)).toEqual(true);
expect(resolvedValue.bufferView).toBeDefined();
expect(rejectedError).toBeUndefined();
});
});
});
Binary file added Specs/Data/Images/Green4x4.crn
Binary file not shown.
23 changes: 22 additions & 1 deletion Specs/Scene/MaterialSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ defineSuite([
renderMaterial(material);
});

it('creates a material with an compressed image uniform', function () {
it('creates a material with an ktx compressed image uniform', function () {
var compressedUrl;
var context = scene.context;
if (context.s3tc) {
Expand All @@ -357,6 +357,8 @@ defineSuite([
compressedUrl = './Data/Images/Green4x4ETC1.ktx';
} else if (context.pvrtc) {
compressedUrl = './Data/Images/Green4x4PVR.ktx';
} else {
return;
}

var material = new Material({
Expand All @@ -371,6 +373,25 @@ defineSuite([
renderMaterial(material);
});

it('creates a material with an crn compressed image uniform', function () {
var context = scene.context;
if (!context.s3tc) {
return;
}

var compressedUrl = './Data/Images/Green4x4.crn';
var material = new Material({
strict : true,
fabric : {
type : 'DiffuseMap',
uniforms : {
image : compressedUrl
}
}
});
renderMaterial(material);
});

it('creates a material with a cube map uniform', function() {
var material = new Material({
strict : true,
Expand Down
1 change: 1 addition & 0 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
var mime = express.static.mime;
mime.define({
'application/json' : ['czml', 'json', 'geojson', 'topojson'],
'image/crn' : ['crn'],
'image/ktx' : ['ktx'],
'model/vnd.gltf+json' : ['gltf'],
'model/vnd.gltf.binary' : ['bgltf', 'glb'],
Expand Down
2 changes: 2 additions & 0 deletions web.config
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
<mimeMap fileExtension=".terrain" mimeType="application/vnd.quantized-mesh" />
<remove fileExtension=".ktx" />
<mimeMap fileExtension=".ktx" mimeType="image/ktx" />
<remove fileExtension=".crn" />
<mimeMap fileExtension=".crn" mimeType="image/crn" />
</staticContent>
</system.webServer>
</configuration>

0 comments on commit ee6856c

Please sign in to comment.