google / node-gles

Apache License 2.0
324 stars 32 forks source link

Error: Argument is not a number! #55

Closed Molay closed 5 years ago

Molay commented 5 years ago

I'm trying to use node-gles with three.js and its WebGLRenderTarget class:

const width = 1920;
const height = 1080;
const renderTarget = new WebGLRenderTarget(width, height, {
  depthBuffer: true,
  stencilBuffer: true,
  format: RGBAFormat
});
renderer.render(scene, camera, renderTarget);

but an error has occurred:

????/node_modules/three/build/three.js:21507
                        _gl.pixelStorei( 37440, texture.flipY );
                            ^

Error: Argument is not a number!
    at uploadTexture (????/node_modules/three/build/three.js:21507:8)
    at setTexture2D (????/node_modules/three/build/three.js:21244:6)
    at setupDepthTexture (????/node_modules/three/build/three.js:21785:4)
    at setupDepthRenderbuffer (????/node_modules/three/build/three.js:21816:5)
    at WebGLTextures.setupRenderTarget (????/node_modules/three/build/three.js:21957:5)
    at WebGLRenderer.setRenderTarget (????/node_modules/three/build/three.js:25482:14)
    at WebGLRenderer.render (????/node_modules/three/build/three.js:24239:10)

In the description of the page WebGLRenderingContext.pixelStorei, the second parameter of method WebGLRenderingContext.pixelStorei can be GLint, GLboolean or GLenum, however the line 3720 of binding/webgl_rendering_context.cc file seems to only support GLint:

https://github.com/google/node-gles/blob/b405d08f114b8a970bc83ec47e95c0786a6ec5e0/binding/webgl_rendering_context.cc#L3720

Maybe using Texture will also have the same problem? I will try it. Using textures will also have the same problem and more. I try to modify the "WebGLRenderingContext::PixelStorei" method to support gl.UNPACK_FLIP_Y_WEBGL with GLboolean value, but it didn't work at all, whatever true or false.

/* static */
napi_value WebGLRenderingContext::PixelStorei(napi_env env,
                                              napi_callback_info info) {
  LOG_CALL("PixelStorei");

  napi_status nstatus;
  size_t argc = 2;
  napi_value args[2];
  napi_value js_this;
  nstatus = napi_get_cb_info(env, info, &argc, args, &js_this, nullptr);
  ENSURE_NAPI_OK_RETVAL(env, nstatus, nullptr);
  ENSURE_ARGC_RETVAL(env, argc, 2, nullptr);

  ENSURE_VALUE_IS_NUMBER_RETVAL(env, args[0], nullptr);
  // ENSURE_VALUE_IS_NUMBER_RETVAL(env, args[1], nullptr);
  napi_valuetype type;
  nstatus = napi_typeof(env, args[1], &type);
  if (nstatus != napi_ok || (type != napi_number && type != napi_boolean)) {
    NapiThrowError(env, "Argument is not a number or boolean!", __FILE__, __LINE__);
    return nullptr;
  }

  WebGLRenderingContext *context = nullptr;
  nstatus = UnwrapContext(env, js_this, &context);
  ENSURE_NAPI_OK_RETVAL(env, nstatus, nullptr);

  GLenum pname;
  nstatus = napi_get_value_uint32(env, args[0], &pname);
  ENSURE_NAPI_OK_RETVAL(env, nstatus, nullptr);

  // GLint param;
  // nstatus = napi_get_value_int32(env, args[1], &param);
  // ENSURE_NAPI_OK_RETVAL(env, nstatus, nullptr);
  //
  // context->eglContextWrapper_->glPixelStorei(pname, param);
  if (type == napi_number) {
    GLint param;
    nstatus = napi_get_value_int32(env, args[1], &param);
    ENSURE_NAPI_OK_RETVAL(env, nstatus, nullptr);

    context->eglContextWrapper_->glPixelStorei(pname, param);
  }
  else if (type == napi_boolean) {
    bool param;
    nstatus = napi_get_value_bool(env, args[1], &param);
    ENSURE_NAPI_OK_RETVAL(env, nstatus, nullptr);

    context->eglContextWrapper_->glPixelStorei(pname, static_cast<GLboolean>(param));
  }

#if DEBUG
  context->CheckForErrors();
#endif
  return nullptr;
}

(gl.UNPACK_FLIP_Y_WEBGL=false) Expectation: texture flip y expectation

(gl.UNPACK_FLIP_Y_WEBGL=false) Result: texture flip y result

macOS 10.14.6, node.js 11.13.0, with node-gles 0.0.14 with three.js 0.107.0

Molay commented 5 years ago

My bad :(

https://stackoverflow.com/questions/15364517/pixelstoreigl-unpack-flip-y-webgl-true

there is no UNPACK_PREMULTIPLY_ALPHA_WEBGL and UNPACK_FLIP_Y_WEBGL in OpenGL ES.

In implementation, WebGL call OpenGL ES to implement js WebGL call, and for these two parameters, WebGL will process on CPU before call OpenGL ES API, which means WebGL using memcpy to flip the image(if flipY is true), then call glTexImage2D.

Summary:

js call gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true). WebGL store it as m_unpackFlipY.

js call gl.texImage2D, WebGL check m_unpackFlipY, if true, flip the image in memory, then call glTexImage2D

I'll try to create a proxy to solve this problem.