mirror of
https://github.com/gre/gl-react.git
synced 2026-01-18 16:16:59 +00:00
1921 lines
67 KiB
C++
Executable File
1921 lines
67 KiB
C++
Executable File
#include "EXGL.h"
|
||
|
||
#ifdef __ANDROID__
|
||
#include <GLES2/gl2.h>
|
||
#include <GLES2/gl2ext.h>
|
||
#include <android/log.h>
|
||
#endif
|
||
#ifdef __APPLE__
|
||
#include <OpenGLES/ES2/gl.h>
|
||
#include <OpenGLES/ES2/glext.h>
|
||
#endif
|
||
|
||
#include <exception>
|
||
#include <future>
|
||
#include <sstream>
|
||
#include <unordered_map>
|
||
#include <vector>
|
||
|
||
#include <JavaScriptCore/JSContextRef.h>
|
||
#include <JavaScriptCore/JSObjectRef.h>
|
||
#include <JavaScriptCore/JSValueRef.h>
|
||
|
||
#include "GLImages.h"
|
||
|
||
#include "EXJSUtils.h"
|
||
#include "EXJSConvertTypedArray.h"
|
||
|
||
#ifdef __APPLE__
|
||
#include "EXiOSUtils.h"
|
||
#endif
|
||
|
||
|
||
// Debugging utilities
|
||
|
||
#define EXGL_DEBUG // Whether debugging is on
|
||
|
||
#ifdef EXGL_DEBUG
|
||
#ifdef __ANDROID__
|
||
#define EXGLSysLog(fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, "EXGL", fmt, ##__VA_ARGS__)
|
||
#endif
|
||
#ifdef __APPLE__
|
||
#define EXGLSysLog(fmt, ...) EXiOSLog("EXGL: " fmt, ##__VA_ARGS__)
|
||
#endif
|
||
#else
|
||
#define EXGLSysLog(...)
|
||
#endif
|
||
|
||
|
||
// Forward declarations
|
||
|
||
class EXGLContext;
|
||
static EXGLContext *EXGLContextGet(EXGLContextId exglCtxId);
|
||
|
||
|
||
// --- EXGLContext -------------------------------------------------------------
|
||
|
||
// Class of the C++ object representing an EXGL rendering context.
|
||
|
||
class EXGLContext {
|
||
private:
|
||
// --- Queue handling --------------------------------------------------------
|
||
|
||
// There are two threads: the input thread (henceforth "JS thread") feeds new GL
|
||
// work, the output thread (henceforth "GL thread", typically UI thread on iOS,
|
||
// GL thread on Android) reads GL work and performs it
|
||
|
||
// By not saving the JS{Global,}Context as a member variable we ensure that no
|
||
// JS work is done on the GL thread
|
||
|
||
// The smallest unit of work
|
||
using Op = std::function<void(void)>;
|
||
|
||
// Ops are combined into batches:
|
||
// 1. A batch is always executed entirely in one go on the GL thread
|
||
// 2. The last add to a batch always precedes the first remove
|
||
// #2 means that it's good to use an std::vector<...> for this
|
||
using Batch = std::vector<Op>;
|
||
|
||
|
||
Batch nextBatch;
|
||
std::vector<Batch> backlog;
|
||
std::mutex backlogMutex;
|
||
|
||
|
||
// [JS thread] Add an Op to the 'next' batch -- the arguments are any form of
|
||
// constructor arguments for Op
|
||
template<typename... Args>
|
||
inline void addToNextBatch(Args &&...args) noexcept {
|
||
nextBatch.emplace_back(std::forward<Args>(args)...);
|
||
}
|
||
|
||
// [JS thread] Send the current 'next' batch to GL and make a new 'next' batch
|
||
void endNextBatch() noexcept {
|
||
std::lock_guard<decltype(backlogMutex)> lock(backlogMutex);
|
||
backlog.emplace_back();
|
||
backlog.back().reserve(nextBatch.size());
|
||
backlog.back().swap(nextBatch);
|
||
}
|
||
|
||
|
||
// [JS thread] Add a blocking operation to the 'next' batch -- waits for the
|
||
// queued function to run before returning
|
||
template<typename F>
|
||
inline void addBlockingToNextBatch(F &&f) noexcept {
|
||
#ifdef __ANDROID__
|
||
// std::packaged_task + std::future segfaults on Android... :|
|
||
|
||
std::mutex mutex;
|
||
std::condition_variable cv;
|
||
auto done = false;
|
||
|
||
addToNextBatch([&] {
|
||
f();
|
||
{
|
||
std::lock_guard<decltype(mutex)> lock(mutex);
|
||
done = true;
|
||
}
|
||
cv.notify_all();
|
||
});
|
||
|
||
{
|
||
std::unique_lock<decltype(mutex)> lock(mutex);
|
||
endNextBatch();
|
||
cv.wait(lock, [&] { return done; });
|
||
}
|
||
#else
|
||
std::packaged_task<decltype(f())(void)> task(std::move(f));
|
||
auto future = task.get_future();
|
||
addToNextBatch([&] { task(); });
|
||
endNextBatch();
|
||
future.wait();
|
||
#endif
|
||
}
|
||
|
||
|
||
// A 'Future' is an opaque return value from a GL method call that is simply
|
||
// fed to other GL method calls. The value is never inspected in JS. This
|
||
// allows us to continue queueing method calls when a method call with a
|
||
// Future return value is encountered: its value won't immediately matter
|
||
// and is only needed when method calls after it ask for the value, and those
|
||
// are queued for even later. This works for GL object id return values such
|
||
// as those from `createShader()`, `createProgram()`, etc.
|
||
|
||
using Future = unsigned int;
|
||
std::unordered_map<Future, GLuint> futures;
|
||
Future nextFuture = 1; // Start at 1 so that Futures are truthy in JS
|
||
|
||
// [JS thread] Enqueue a function and return a Future that will have its
|
||
// result when the function is called
|
||
template<typename F>
|
||
inline JSValueRef addFutureToNextBatch(JSContextRef jsCtx, F &&f) noexcept {
|
||
auto future = nextFuture++;
|
||
addToNextBatch([=] {
|
||
//assert(futures.find(future) == futures.end()); // FIXME gre commented – for some reason, breaks in android
|
||
futures[future] = f();
|
||
});
|
||
return JSValueMakeNumber(jsCtx, future);
|
||
}
|
||
|
||
// [GL thread] Get the value in a Future
|
||
inline GLuint peekFuture(Future future) const {
|
||
auto iter = futures.find(future);
|
||
if (iter == futures.end()) {
|
||
return 0;
|
||
}
|
||
return iter->second;
|
||
}
|
||
|
||
|
||
// [GL thread] Do all the remaining work we can do on the GL thread
|
||
public:
|
||
void flush(void) noexcept {
|
||
// Keep a copy and clear backlog to minimize lock time
|
||
decltype(backlog) copy;
|
||
{
|
||
std::lock_guard<decltype(backlogMutex)> lock(backlogMutex);
|
||
backlog.swap(copy);
|
||
}
|
||
for (const auto &batch : copy) {
|
||
for (const auto &op : batch) {
|
||
op();
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// --- Init/destroy and JS object binding ------------------------------------
|
||
private:
|
||
JSObjectRef jsGl;
|
||
|
||
public:
|
||
EXGLContext(JSGlobalContextRef jsCtx, EXGLContextId exglCtxId) {
|
||
// Prepare for TypedArray usage
|
||
prepareTypedArrayAPI(jsCtx);
|
||
|
||
// Create JS version of us
|
||
auto jsClass = JSClassCreate(&kJSClassDefinitionEmpty);
|
||
jsGl = JSObjectMake(jsCtx, jsClass, (void *) (intptr_t) exglCtxId);
|
||
JSClassRelease(jsClass);
|
||
installMethods(jsCtx);
|
||
installConstants(jsCtx);
|
||
|
||
// Clear everything to initial values
|
||
addToNextBatch([this] {
|
||
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
|
||
glClearColor(0, 0, 0, 0);
|
||
glClearDepthf(1);
|
||
glClearStencil(0);
|
||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||
});
|
||
}
|
||
|
||
JSObjectRef getJSObject(void) const noexcept {
|
||
return jsGl;
|
||
}
|
||
|
||
|
||
// --- GL state --------------------------------------------------------------
|
||
private:
|
||
GLint defaultFramebuffer = 0;
|
||
bool unpackFLipY = false;
|
||
|
||
public:
|
||
void setDefaultFramebuffer(GLint framebuffer) {
|
||
defaultFramebuffer = framebuffer;
|
||
}
|
||
|
||
|
||
// --- Actual GL bindings ----------------------------------------------------
|
||
private:
|
||
|
||
// Constants in WebGL that aren't in OpenGL ES
|
||
// https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Constants
|
||
|
||
#define GL_UNPACK_FLIP_Y_WEBGL 0x9240
|
||
#define GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL 0x9241
|
||
#define GL_CONTEXT_LOST_WEBGL 0x9242
|
||
#define GL_UNPACK_COLORSPACE_CONVERSION_WEBGL 0x9243
|
||
#define GL_BROWSER_DEFAULT_WEBGL 0x9244
|
||
|
||
#define GL_STENCIL_INDEX 0x1901
|
||
#define GL_DEPTH_STENCIL 0x84F9
|
||
#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
|
||
|
||
|
||
// Utilities
|
||
|
||
static inline void jsThrow(JSContextRef jsCtx, const char *msg, JSValueRef *jsException) {
|
||
*jsException = JSValueToObject(jsCtx, EXJSValueMakeStringFromUTF8CString(jsCtx, msg), nullptr);
|
||
}
|
||
|
||
static inline std::shared_ptr<char> jsValueToSharedStr(JSContextRef jsCtx, JSValueRef jsVal) noexcept {
|
||
return std::shared_ptr<char>(EXJSValueToUTF8CStringMalloc(jsCtx, jsVal, nullptr), free);
|
||
}
|
||
|
||
static inline void *bufferOffset(GLint offset) noexcept {
|
||
return (char *) 0 + offset;
|
||
}
|
||
|
||
static inline GLuint bytesPerPixel(GLenum type, GLenum format) {
|
||
int bytesPerComponent = 0;
|
||
switch (type) {
|
||
case GL_UNSIGNED_BYTE:
|
||
bytesPerComponent = 1;
|
||
break;
|
||
case GL_FLOAT:
|
||
bytesPerComponent = 4;
|
||
break;
|
||
case GL_HALF_FLOAT_OES:
|
||
bytesPerComponent = 2;
|
||
break;
|
||
case GL_UNSIGNED_SHORT_5_6_5:
|
||
case GL_UNSIGNED_SHORT_4_4_4_4:
|
||
case GL_UNSIGNED_SHORT_5_5_5_1:
|
||
return 2;
|
||
}
|
||
|
||
switch (format) {
|
||
case GL_LUMINANCE:
|
||
case GL_ALPHA:
|
||
return 1 * bytesPerComponent;
|
||
case GL_LUMINANCE_ALPHA:
|
||
return 2 * bytesPerComponent;
|
||
case GL_RGB:
|
||
return 3 * bytesPerComponent;
|
||
case GL_RGBA:
|
||
return 4 * bytesPerComponent;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static inline void flipPixels(GLubyte *pixels, size_t bytesPerRow, size_t rows) {
|
||
if (!pixels) {
|
||
return;
|
||
}
|
||
|
||
GLuint middle = rows / 2;
|
||
GLuint intsPerRow = bytesPerRow / sizeof(GLuint);
|
||
GLuint remainingBytes = bytesPerRow - intsPerRow * sizeof(GLuint);
|
||
|
||
for (GLuint rowTop = 0, rowBottom = rows - 1; rowTop < middle; ++rowTop, --rowBottom) {
|
||
// Swap in packs of sizeof(GLuint) bytes
|
||
GLuint *iTop = (GLuint *) (pixels + rowTop * bytesPerRow);
|
||
GLuint *iBottom = (GLuint *) (pixels + rowBottom * bytesPerRow);
|
||
GLuint iTmp;
|
||
GLuint n = intsPerRow;
|
||
do {
|
||
iTmp = *iTop;
|
||
*iTop++ = *iBottom;
|
||
*iBottom++ = iTmp;
|
||
} while(--n > 0);
|
||
|
||
// Swap remainder bytes
|
||
GLubyte *bTop = (GLubyte *) iTop;
|
||
GLubyte *bBottom = (GLubyte *) iBottom;
|
||
GLubyte bTmp;
|
||
switch (remainingBytes) {
|
||
case 3: bTmp = *bTop; *bTop++ = *bBottom; *bBottom++ = bTmp;
|
||
case 2: bTmp = *bTop; *bTop++ = *bBottom; *bBottom++ = bTmp;
|
||
case 1: bTmp = *bTop; *bTop = *bBottom; *bBottom = bTmp;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// TypedArray API wrapping
|
||
|
||
bool usingTypedArrayHack = false;
|
||
|
||
inline void prepareTypedArrayAPI(JSContextRef jsCtx) {
|
||
#ifdef __APPLE__
|
||
// iOS >= 10 has built-in C TypedArray API
|
||
if (EXiOSGetOperatingSystemVersion().majorVersion >= 10) {
|
||
return;
|
||
}
|
||
#endif
|
||
|
||
JSContextPrepareTypedArrayAPI(jsCtx);
|
||
usingTypedArrayHack = true;
|
||
}
|
||
|
||
inline std::shared_ptr<void> jsValueToSharedArray(JSContextRef jsCtx, JSValueRef jsVal,
|
||
size_t *pByteLength) noexcept {
|
||
if (usingTypedArrayHack) {
|
||
return std::shared_ptr<void>(JSObjectGetTypedArrayDataMalloc(jsCtx, (JSObjectRef) jsVal,
|
||
pByteLength), free);
|
||
} else {
|
||
JSObjectRef jsObject = (JSObjectRef) jsVal;
|
||
|
||
size_t byteLength = JSObjectGetTypedArrayByteLength(jsCtx, jsObject, nullptr);
|
||
if (pByteLength) {
|
||
*pByteLength = byteLength;
|
||
}
|
||
|
||
void *data = JSObjectGetTypedArrayBytesPtr(jsCtx, jsObject, nullptr);
|
||
if (!data) {
|
||
return std::shared_ptr<void>(nullptr);
|
||
}
|
||
|
||
// Copy data since it's unclear how long JavaScriptCore's buffer will live
|
||
// TODO(nikki): See if we can just pin/unpin and not copy?
|
||
void *dataMalloc = malloc(byteLength);
|
||
memcpy(dataMalloc, data, byteLength);
|
||
return std::shared_ptr<void>(dataMalloc, free);
|
||
}
|
||
}
|
||
|
||
static void jsTypedArrayFreeDeallocator(void *data, void *ctx) {
|
||
free(data);
|
||
}
|
||
|
||
inline JSValueRef makeTypedArray(JSContextRef jsCtx, JSTypedArrayType arrayType,
|
||
void *data, size_t byteLength) {
|
||
if (data) {
|
||
if (usingTypedArrayHack) {
|
||
return JSObjectMakeTypedArrayWithData(jsCtx, arrayType, data, byteLength);
|
||
} else {
|
||
void *dataMalloc = malloc(byteLength);
|
||
memcpy(dataMalloc, data, byteLength);
|
||
return JSObjectMakeTypedArrayWithBytesNoCopy(jsCtx, arrayType, dataMalloc, byteLength,
|
||
jsTypedArrayFreeDeallocator, nullptr, nullptr);
|
||
}
|
||
} else {
|
||
if (usingTypedArrayHack) {
|
||
return JSObjectMakeTypedArrayWithHack(jsCtx, arrayType, 0);
|
||
} else {
|
||
return JSObjectMakeTypedArray(jsCtx, arrayType, 0, nullptr);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// Standard method wrapper, run on JS thread, return a value
|
||
#define _WRAP_METHOD(name, minArgc) \
|
||
static JSValueRef exglNativeStatic_##name(JSContextRef jsCtx, \
|
||
JSObjectRef jsFunction, \
|
||
JSObjectRef jsThis, \
|
||
size_t jsArgc, \
|
||
const JSValueRef jsArgv[], \
|
||
JSValueRef* jsException) \
|
||
{ \
|
||
auto exglCtx = EXGLContextGet((EXGLContextId) (intptr_t) \
|
||
JSObjectGetPrivate(jsThis)); \
|
||
if (!exglCtx) { \
|
||
return nullptr; \
|
||
} \
|
||
try { \
|
||
if (jsArgc < minArgc) { \
|
||
throw std::runtime_error("EXGL: Too few arguments to " #name "()!"); \
|
||
} \
|
||
return exglCtx->exglNativeInstance_##name(jsCtx, jsFunction, jsThis, \
|
||
jsArgc, jsArgv, jsException); \
|
||
} catch (const std::exception &e) { \
|
||
exglCtx->jsThrow(jsCtx, e.what(), jsException); \
|
||
return nullptr; \
|
||
} \
|
||
} \
|
||
inline JSValueRef exglNativeInstance_##name(JSContextRef jsCtx, \
|
||
JSObjectRef jsFunction, \
|
||
JSObjectRef jsThis, \
|
||
size_t jsArgc, \
|
||
const JSValueRef jsArgv[], \
|
||
JSValueRef* jsException)
|
||
|
||
// Wrapper raises an exception saying the function isn't implemented yet
|
||
#define _WRAP_METHOD_UNIMPL(name) \
|
||
_WRAP_METHOD(name, 0) { \
|
||
throw std::runtime_error("EXGL: " #name "() isn't implemented yet!"); \
|
||
return nullptr; \
|
||
}
|
||
|
||
// Wrapper that takes only scalar arguments and returns nothing
|
||
#define _WRAP_METHOD_SIMPLE(name, glFunc, ...) \
|
||
_WRAP_METHOD(name, EXJS_ARGC(__VA_ARGS__)) { \
|
||
addToNextBatch(std::bind(glFunc, EXJS_MAP_EXT(0, _EXJS_COMMA, _WRAP_METHOD_SIMPLE_UNPACK, __VA_ARGS__))); \
|
||
return nullptr; \
|
||
}
|
||
#define _WRAP_METHOD_SIMPLE_UNPACK(i, _) EXJSValueToNumberFast(jsCtx, jsArgv[i])
|
||
|
||
|
||
// This listing follows the order in
|
||
// https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext
|
||
|
||
|
||
// The WebGL context
|
||
// -----------------
|
||
|
||
_WRAP_METHOD(getContextAttributes, 0) {
|
||
auto jsResult = JSObjectMake(jsCtx, nullptr, nullptr);
|
||
EXJSObjectSetValueWithUTF8CStringName(jsCtx, jsResult, "alpha",
|
||
JSValueMakeBoolean(jsCtx, true));
|
||
EXJSObjectSetValueWithUTF8CStringName(jsCtx, jsResult, "depth",
|
||
JSValueMakeBoolean(jsCtx, true));
|
||
EXJSObjectSetValueWithUTF8CStringName(jsCtx, jsResult, "stencil",
|
||
JSValueMakeBoolean(jsCtx, false));
|
||
EXJSObjectSetValueWithUTF8CStringName(jsCtx, jsResult, "antialias",
|
||
JSValueMakeBoolean(jsCtx, false));
|
||
EXJSObjectSetValueWithUTF8CStringName(jsCtx, jsResult, "premultipliedAlpha",
|
||
JSValueMakeBoolean(jsCtx, false));
|
||
return jsResult;
|
||
}
|
||
|
||
_WRAP_METHOD(isContextLost, 0) {
|
||
return JSValueMakeBoolean(jsCtx, false);
|
||
}
|
||
|
||
|
||
// Viewing and clipping
|
||
// --------------------
|
||
|
||
_WRAP_METHOD_SIMPLE(scissor, glScissor, x, y, width, height)
|
||
|
||
_WRAP_METHOD_SIMPLE(viewport, glViewport, x, y, width, height)
|
||
|
||
|
||
// State information
|
||
// -----------------
|
||
|
||
_WRAP_METHOD_SIMPLE(activeTexture, glActiveTexture, texture)
|
||
|
||
_WRAP_METHOD_SIMPLE(blendColor, glBlendColor, red, green, blue, alpha)
|
||
|
||
_WRAP_METHOD_SIMPLE(blendEquation, glBlendEquation, mode)
|
||
|
||
_WRAP_METHOD_SIMPLE(blendEquationSeparate, glBlendEquationSeparate, modeRGB, modeAlpha)
|
||
|
||
_WRAP_METHOD_SIMPLE(blendFunc, glBlendFunc, sfactor, dfactor)
|
||
|
||
_WRAP_METHOD_SIMPLE(blendFuncSeparate, glBlendFuncSeparate, srcRGB, dstRGB, srcAlpha, dstAlpha)
|
||
|
||
_WRAP_METHOD_SIMPLE(clearColor, glClearColor, red, green, blue, alpha)
|
||
|
||
_WRAP_METHOD_SIMPLE(clearDepth, glClearDepthf, depth)
|
||
|
||
_WRAP_METHOD_SIMPLE(clearStencil, glClearStencil, s)
|
||
|
||
_WRAP_METHOD_SIMPLE(colorMask, glColorMask, red, green, blue, alpha)
|
||
|
||
_WRAP_METHOD_SIMPLE(cullFace, glCullFace, mode)
|
||
|
||
_WRAP_METHOD_SIMPLE(depthFunc, glDepthFunc, func)
|
||
|
||
_WRAP_METHOD_SIMPLE(depthMask, glDepthMask, flag)
|
||
|
||
_WRAP_METHOD_SIMPLE(depthRange, glDepthRangef, zNear, zFar)
|
||
|
||
_WRAP_METHOD_SIMPLE(disable, glDisable, cap)
|
||
|
||
_WRAP_METHOD_SIMPLE(enable, glEnable, cap)
|
||
|
||
_WRAP_METHOD_SIMPLE(frontFace, glFrontFace, mode)
|
||
|
||
template<typename T, size_t dim, typename F>
|
||
inline JSValueRef getParameterArray(JSContextRef jsCtx, JSTypedArrayType arrayType,
|
||
F &&glGetFunc, GLenum pname) {
|
||
T glResults[dim];
|
||
addBlockingToNextBatch([&] { glGetFunc(pname, glResults); });
|
||
return makeTypedArray(jsCtx, arrayType, glResults, sizeof(glResults));
|
||
}
|
||
|
||
_WRAP_METHOD(getParameter, 1) {
|
||
EXJS_UNPACK_ARGV(GLenum pname);
|
||
switch (pname) {
|
||
// Float32Array[0]
|
||
case GL_COMPRESSED_TEXTURE_FORMATS:
|
||
return makeTypedArray(jsCtx, kJSTypedArrayTypeFloat32Array, nullptr, 0);
|
||
|
||
// FLoat32Array[2]
|
||
case GL_ALIASED_LINE_WIDTH_RANGE:
|
||
case GL_ALIASED_POINT_SIZE_RANGE:
|
||
case GL_DEPTH_RANGE:
|
||
return getParameterArray<GLfloat, 2>(jsCtx, kJSTypedArrayTypeFloat32Array, &glGetFloatv, pname);
|
||
// FLoat32Array[4]
|
||
case GL_BLEND_COLOR:
|
||
case GL_COLOR_CLEAR_VALUE:
|
||
return getParameterArray<GLfloat, 4>(jsCtx, kJSTypedArrayTypeFloat32Array, &glGetFloatv, pname);
|
||
|
||
// Int32Array[2]
|
||
case GL_MAX_VIEWPORT_DIMS:
|
||
return getParameterArray<GLint, 2>(jsCtx, kJSTypedArrayTypeInt32Array, &glGetIntegerv, pname);
|
||
// Int32Array[4]
|
||
case GL_SCISSOR_BOX:
|
||
case GL_VIEWPORT:
|
||
return getParameterArray<GLint, 4>(jsCtx, kJSTypedArrayTypeInt32Array, &glGetIntegerv, pname);
|
||
|
||
// boolean[4]
|
||
case GL_COLOR_WRITEMASK: {
|
||
GLint glResults[4];
|
||
addBlockingToNextBatch([&] { glGetIntegerv(pname, glResults); });
|
||
JSValueRef jsResults[4];
|
||
for (unsigned int i = 0; i < 4; ++i) {
|
||
jsResults[i] = JSValueMakeBoolean(jsCtx, glResults[i]);
|
||
}
|
||
return JSObjectMakeArray(jsCtx, 4, jsResults, nullptr);
|
||
}
|
||
|
||
// boolean
|
||
case GL_UNPACK_FLIP_Y_WEBGL:
|
||
return JSValueMakeBoolean(jsCtx, unpackFLipY);
|
||
case GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL:
|
||
case GL_UNPACK_COLORSPACE_CONVERSION_WEBGL:
|
||
return JSValueMakeBoolean(jsCtx, false);
|
||
|
||
// string
|
||
case GL_RENDERER:
|
||
case GL_SHADING_LANGUAGE_VERSION:
|
||
case GL_VENDOR:
|
||
case GL_VERSION: {
|
||
const GLubyte *glStr;
|
||
addBlockingToNextBatch([&] { glStr = glGetString(pname); });
|
||
return EXJSValueMakeStringFromUTF8CString(jsCtx, (const char *) glStr);
|
||
}
|
||
|
||
// float
|
||
case GL_DEPTH_CLEAR_VALUE:
|
||
case GL_LINE_WIDTH:
|
||
case GL_POLYGON_OFFSET_FACTOR:
|
||
case GL_POLYGON_OFFSET_UNITS:
|
||
case GL_SAMPLE_COVERAGE_VALUE: {
|
||
GLfloat glFloat;
|
||
addBlockingToNextBatch([&] { glGetFloatv(pname, &glFloat); });
|
||
return JSValueMakeNumber(jsCtx, glFloat);
|
||
}
|
||
|
||
// Future
|
||
case GL_ARRAY_BUFFER_BINDING:
|
||
case GL_ELEMENT_ARRAY_BUFFER_BINDING:
|
||
case GL_CURRENT_PROGRAM: {
|
||
GLint glInt;
|
||
addBlockingToNextBatch([&] { glGetIntegerv(pname, &glInt); });
|
||
for (const auto &pair : futures) {
|
||
if (pair.second == glInt) {
|
||
return JSValueMakeNumber(jsCtx, pair.first);
|
||
}
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
// Unimplemented...
|
||
#define _GET_PARAMETER_UNIMPL(param) \
|
||
case GL_##param: \
|
||
throw std::runtime_error("EXGL: getParameter() doesn't support gl." \
|
||
#param " yet!");
|
||
_GET_PARAMETER_UNIMPL(FRAMEBUFFER_BINDING);
|
||
_GET_PARAMETER_UNIMPL(RENDERBUFFER_BINDING);
|
||
_GET_PARAMETER_UNIMPL(TEXTURE_BINDING_2D);
|
||
_GET_PARAMETER_UNIMPL(TEXTURE_BINDING_CUBE_MAP);
|
||
#undef _GET_PARAMETER_UNIMPL
|
||
|
||
// int
|
||
default: {
|
||
GLint glInt;
|
||
addBlockingToNextBatch([&] { glGetIntegerv(pname, &glInt); });
|
||
return JSValueMakeNumber(jsCtx, glInt);
|
||
}
|
||
}
|
||
}
|
||
|
||
_WRAP_METHOD(getError, 0) {
|
||
GLenum glResult;
|
||
addBlockingToNextBatch([&] { glResult = glGetError(); });
|
||
return JSValueMakeNumber(jsCtx, glResult);
|
||
}
|
||
|
||
_WRAP_METHOD_SIMPLE(hint, glHint, target, mode)
|
||
|
||
_WRAP_METHOD(isEnabled, 1) {
|
||
EXJS_UNPACK_ARGV(GLenum cap);
|
||
GLboolean glResult;
|
||
addBlockingToNextBatch([&] { glResult = glIsEnabled(cap); });
|
||
return JSValueMakeBoolean(jsCtx, glResult);
|
||
}
|
||
|
||
_WRAP_METHOD_SIMPLE(lineWidth, glLineWidth, width)
|
||
|
||
_WRAP_METHOD(pixelStorei, 2) {
|
||
EXJS_UNPACK_ARGV(GLenum pname, GLint param);
|
||
switch (pname) {
|
||
case GL_UNPACK_FLIP_Y_WEBGL:
|
||
unpackFLipY = param;
|
||
break;
|
||
default:
|
||
EXGLSysLog("EXGL: gl.pixelStorei() doesn't support this parameter yet!");
|
||
break;
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD_SIMPLE(polygonOffset, glPolygonOffset, factor, units)
|
||
|
||
_WRAP_METHOD_SIMPLE(sampleCoverage, glSampleCoverage, value, invert)
|
||
|
||
_WRAP_METHOD_SIMPLE(stencilFunc, glStencilFunc, func, ref, mask)
|
||
|
||
_WRAP_METHOD_SIMPLE(stencilFuncSeparate, glStencilFuncSeparate, face, func, ref, mask)
|
||
|
||
_WRAP_METHOD_SIMPLE(stencilMask, glStencilMask, mask)
|
||
|
||
_WRAP_METHOD_SIMPLE(stencilMaskSeparate, glStencilMaskSeparate, face, mask)
|
||
|
||
_WRAP_METHOD_SIMPLE(stencilOp, glStencilOp, fail, zfail, zpass)
|
||
|
||
_WRAP_METHOD_SIMPLE(stencilOpSeparate, glStencilOpSeparate, face, fail, zfail, zpass)
|
||
|
||
|
||
// Buffers
|
||
// -------
|
||
|
||
_WRAP_METHOD(bindBuffer, 2) {
|
||
EXJS_UNPACK_ARGV(GLenum target, Future fBuffer);
|
||
addToNextBatch([=] { glBindBuffer(target, peekFuture(fBuffer)); });
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(bufferData, 3) {
|
||
GLenum target = EXJSValueToNumberFast(jsCtx, jsArgv[0]);
|
||
auto jsSecond = jsArgv[1];
|
||
GLenum usage = EXJSValueToNumberFast(jsCtx, jsArgv[2]);
|
||
|
||
if (JSValueIsNumber(jsCtx, jsSecond)) {
|
||
GLsizeiptr length = EXJSValueToNumberFast(jsCtx, jsSecond);
|
||
addToNextBatch([=] { glBufferData(target, length, nullptr, usage); });
|
||
} else if (JSValueIsNull(jsCtx, jsSecond)) {
|
||
addToNextBatch([=] { glBufferData(target, 0, nullptr, usage); });
|
||
} else {
|
||
size_t length;
|
||
auto data = jsValueToSharedArray(jsCtx, jsSecond, &length);
|
||
addToNextBatch([=] { glBufferData(target, length, data.get(), usage); });
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(bufferSubData, 3) {
|
||
if (!JSValueIsNull(jsCtx, jsArgv[2])) {
|
||
EXJS_UNPACK_ARGV(GLenum target, GLintptr offset);
|
||
size_t length;
|
||
auto data = jsValueToSharedArray(jsCtx, jsArgv[2], &length);
|
||
addToNextBatch([=] { glBufferSubData(target, offset, length, data.get()); });
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(createBuffer, 0) {
|
||
return addFutureToNextBatch(jsCtx, [] {
|
||
GLuint buffer;
|
||
glGenBuffers(1, &buffer);
|
||
return buffer;
|
||
});
|
||
}
|
||
|
||
_WRAP_METHOD(deleteBuffer, 1) {
|
||
EXJS_UNPACK_ARGV(Future fBuffer);
|
||
addToNextBatch([=] {
|
||
GLuint buffer = peekFuture(fBuffer);
|
||
glDeleteBuffers(1, &buffer);
|
||
});
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(getBufferParameter, 2) {
|
||
EXJS_UNPACK_ARGV(GLenum target, GLenum pname);
|
||
GLint glResult;
|
||
addBlockingToNextBatch([&] { glGetBufferParameteriv(target, pname, &glResult); });
|
||
return JSValueMakeNumber(jsCtx, glResult);
|
||
}
|
||
|
||
#define _WRAP_METHOD_IS_OBJECT(type) \
|
||
_WRAP_METHOD(is ## type, 1) { \
|
||
EXJS_UNPACK_ARGV(Future f); \
|
||
GLboolean glResult; \
|
||
addBlockingToNextBatch([&] { \
|
||
glResult = glIs ## type(peekFuture(f)); \
|
||
}); \
|
||
return JSValueMakeBoolean(jsCtx, glResult); \
|
||
}
|
||
|
||
_WRAP_METHOD_IS_OBJECT(Buffer)
|
||
|
||
|
||
// Framebuffers
|
||
// ------------
|
||
|
||
_WRAP_METHOD(bindFramebuffer, 2) {
|
||
EXJS_UNPACK_ARGV(GLenum target);
|
||
if (JSValueIsNull(jsCtx, jsArgv[1])) {
|
||
addToNextBatch([=] { glBindFramebuffer(target, defaultFramebuffer); });
|
||
} else {
|
||
Future fFramebuffer = EXJSValueToNumberFast(jsCtx, jsArgv[1]);
|
||
addToNextBatch([=] { glBindFramebuffer(target, peekFuture(fFramebuffer)); });
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(checkFramebufferStatus, 1) {
|
||
GLenum glResult;
|
||
EXJS_UNPACK_ARGV(GLenum target);
|
||
addBlockingToNextBatch([&] { glResult = glCheckFramebufferStatus(target); });
|
||
return JSValueMakeNumber(jsCtx, glResult);
|
||
}
|
||
|
||
_WRAP_METHOD(createFramebuffer, 0) {
|
||
return addFutureToNextBatch(jsCtx, [] {
|
||
GLuint framebuffer;
|
||
glGenFramebuffers(1, &framebuffer);
|
||
return framebuffer;
|
||
});
|
||
}
|
||
|
||
_WRAP_METHOD(deleteFramebuffer, 1) {
|
||
EXJS_UNPACK_ARGV(Future fFramebuffer);
|
||
addToNextBatch([=] {
|
||
GLuint framebuffer = peekFuture(fFramebuffer);
|
||
glDeleteFramebuffers(1, &framebuffer);
|
||
});
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD_UNIMPL(framebufferRenderbuffer)
|
||
|
||
_WRAP_METHOD(framebufferTexture2D, 5) {
|
||
EXJS_UNPACK_ARGV(GLenum target, GLenum attachment, GLenum textarget, Future fTexture, GLint level);
|
||
addToNextBatch([=] {
|
||
glFramebufferTexture2D(target, attachment, textarget, peekFuture(fTexture), level);
|
||
});
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD_UNIMPL(getFramebufferAttachmentParameter)
|
||
|
||
_WRAP_METHOD_IS_OBJECT(Framebuffer)
|
||
|
||
_WRAP_METHOD(readPixels, 7) {
|
||
EXJS_UNPACK_ARGV(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type);
|
||
if (usingTypedArrayHack) {
|
||
size_t byteLength = width * height * bytesPerPixel(type, format);
|
||
auto pixels = std::shared_ptr<void>(malloc(byteLength), free);
|
||
addBlockingToNextBatch([&] {
|
||
glReadPixels(x, y, width, height, format, type, pixels.get());
|
||
});
|
||
JSObjectSetTypedArrayData(jsCtx, (JSObjectRef) jsArgv[6], pixels.get(), byteLength);
|
||
} else {
|
||
void *pixels = JSObjectGetTypedArrayBytesPtr(jsCtx, (JSObjectRef) jsArgv[6], nullptr);
|
||
addBlockingToNextBatch([&] {
|
||
glReadPixels(x, y, width, height, format, type, pixels);
|
||
});
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
|
||
// Renderbuffers
|
||
// -------------
|
||
|
||
_WRAP_METHOD_UNIMPL(bindRenderbuffer)
|
||
|
||
_WRAP_METHOD_UNIMPL(createRenderbuffer)
|
||
|
||
_WRAP_METHOD_UNIMPL(deleteRenderbuffer)
|
||
|
||
_WRAP_METHOD_UNIMPL(getRenderbufferParameter)
|
||
|
||
_WRAP_METHOD_IS_OBJECT(Renderbuffer)
|
||
|
||
_WRAP_METHOD_UNIMPL(renderbufferStorage)
|
||
|
||
|
||
// Textures
|
||
// --------
|
||
|
||
_WRAP_METHOD(bindTexture, 2) {
|
||
EXJS_UNPACK_ARGV(GLenum target);
|
||
if (JSValueIsNull(jsCtx, jsArgv[1])) {
|
||
addToNextBatch(std::bind(glBindTexture, target, 0));
|
||
} else {
|
||
Future fTexture = EXJSValueToNumberFast(jsCtx, jsArgv[1]);
|
||
addToNextBatch([=] { glBindTexture(target, peekFuture(fTexture)); });
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD_UNIMPL(compressedTexImage2D)
|
||
|
||
_WRAP_METHOD_UNIMPL(compressedTexSubImage2D)
|
||
|
||
_WRAP_METHOD_SIMPLE(copyTexImage2D, glCopyTexImage2D,
|
||
target, level, internalformat,
|
||
x, y, width, height, border)
|
||
|
||
_WRAP_METHOD_SIMPLE(copyTexSubImage2D, glCopyTexSubImage2D,
|
||
target, level,
|
||
xoffset, yoffset, x, y, width, height)
|
||
|
||
_WRAP_METHOD(createTexture, 0) {
|
||
return addFutureToNextBatch(jsCtx, [] {
|
||
GLuint texture;
|
||
glGenTextures(1, &texture);
|
||
return texture;
|
||
});
|
||
}
|
||
|
||
_WRAP_METHOD(deleteTexture, 1) {
|
||
EXJS_UNPACK_ARGV(Future fTexture);
|
||
addToNextBatch([=] {
|
||
GLuint texture = peekFuture(fTexture);
|
||
glDeleteTextures(1, &texture);
|
||
});
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD_SIMPLE(generateMipmap, glGenerateMipmap, target)
|
||
|
||
_WRAP_METHOD_UNIMPL(getTexParameter)
|
||
|
||
_WRAP_METHOD_IS_OBJECT(Texture)
|
||
|
||
_WRAP_METHOD(texImage2D, 6) {
|
||
if (jsArgc == 9) {
|
||
// 9-argument version
|
||
EXJS_UNPACK_ARGV(GLenum target, GLint level, GLint internalformat,
|
||
GLsizei width, GLsizei height, GLsizei border,
|
||
GLenum format, GLenum type);
|
||
// Null?
|
||
if (JSValueIsNull(jsCtx, jsArgv[8])) {
|
||
addToNextBatch([=] {
|
||
glTexImage2D(target, level, internalformat,
|
||
width, height, border,
|
||
format, type, nullptr);
|
||
});
|
||
return nullptr;
|
||
}
|
||
|
||
JSObjectRef jsPixels = (JSObjectRef) jsArgv[8];
|
||
|
||
// Raw texture data TypedArray?
|
||
{
|
||
auto data = jsValueToSharedArray(jsCtx, jsPixels, nullptr);
|
||
if (data) {
|
||
if (unpackFLipY) {
|
||
flipPixels((GLubyte *) data.get(), width * bytesPerPixel(type, format), height);
|
||
}
|
||
addToNextBatch([=] {
|
||
glTexImage2D(target, level, internalformat,
|
||
width, height, border,
|
||
format, type, data.get());
|
||
});
|
||
return nullptr;
|
||
}
|
||
}
|
||
|
||
throw std::runtime_error("EXGL: Invalid pixel data argument for"
|
||
" gl.texImage2D()!");
|
||
} else if (jsArgc == 6) {
|
||
EXJS_UNPACK_ARGV(GLenum target, GLint level, GLint internalformat,
|
||
GLenum format, GLenum type);
|
||
JSObjectRef jsPixels = (JSObjectRef) jsArgv[5];
|
||
|
||
// GLAsset object ?
|
||
|
||
JSValueRef jsGlAssetId = EXJSObjectGetPropertyNamed(jsCtx, jsPixels, "glAssetId");
|
||
if (jsGlAssetId && JSValueIsNumber(jsCtx, jsGlAssetId)) {
|
||
int glAssetId = (int)JSValueToNumber(jsCtx, jsGlAssetId, NULL);
|
||
GLAsset *asset = GLImagesGet(glAssetId);
|
||
if (!asset) {
|
||
throw std::runtime_error("EXGL: gl.texImage2D: asset not found");
|
||
}
|
||
void *data;
|
||
int width = asset->width;
|
||
int height = asset->height;
|
||
if (unpackFLipY) {
|
||
data = asset->lazyFlippedData;
|
||
if (!data) {
|
||
int bpp = 4; // GLAsset convention
|
||
int bytes = width * height * bpp;
|
||
data = malloc(bytes);
|
||
memcpy(data, asset->data, bytes);
|
||
flipPixels((GLubyte *) data, width * bpp, height);
|
||
asset->lazyFlippedData = data;
|
||
}
|
||
}
|
||
else {
|
||
data = asset->data;
|
||
}
|
||
addToNextBatch([=] {
|
||
glTexImage2D(target, level, internalformat,
|
||
width, height, 0,
|
||
format, type, data);
|
||
});
|
||
return nullptr;
|
||
}
|
||
|
||
throw std::runtime_error("EXGL: Invalid pixel data argument for"
|
||
" gl.texImage2D()!");
|
||
} else {
|
||
throw std::runtime_error("EXGL: Invalid number of arguments to gl.texImage2D()!");
|
||
}
|
||
}
|
||
|
||
_WRAP_METHOD_UNIMPL(texSubImage2D)
|
||
|
||
_WRAP_METHOD_SIMPLE(texParameterf, glTexParameterf, target, pname, param)
|
||
|
||
_WRAP_METHOD_SIMPLE(texParameteri, glTexParameteri, target, pname, param)
|
||
|
||
|
||
// Programs and shaders
|
||
// --------------------
|
||
|
||
_WRAP_METHOD(attachShader, 2) {
|
||
EXJS_UNPACK_ARGV(Future fProgram, Future fShader);
|
||
addToNextBatch([=] { glAttachShader(peekFuture(fProgram), peekFuture(fShader)); });
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(bindAttribLocation, 3) {
|
||
EXJS_UNPACK_ARGV(Future fProgram, GLuint index);
|
||
auto name = jsValueToSharedStr(jsCtx, jsArgv[2]);
|
||
addToNextBatch([=] { glBindAttribLocation(peekFuture(fProgram), index, name.get()); });
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(compileShader, 1) {
|
||
EXJS_UNPACK_ARGV(Future fShader);
|
||
addToNextBatch([=] { glCompileShader(peekFuture(fShader)); });
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(createProgram, 0) {
|
||
return addFutureToNextBatch(jsCtx, &glCreateProgram);
|
||
}
|
||
|
||
_WRAP_METHOD(createShader, 1) {
|
||
EXJS_UNPACK_ARGV(GLenum type);
|
||
if (type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER) {
|
||
return addFutureToNextBatch(jsCtx, std::bind(glCreateShader, type));
|
||
} else {
|
||
return JSValueMakeNull(jsCtx);
|
||
}
|
||
}
|
||
|
||
_WRAP_METHOD(deleteProgram, 1) {
|
||
EXJS_UNPACK_ARGV(Future fProgram);
|
||
addToNextBatch([=] { glDeleteProgram(peekFuture(fProgram)); });
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(deleteShader, 1) {
|
||
EXJS_UNPACK_ARGV(Future fShader);
|
||
addToNextBatch([=] { glDeleteShader(peekFuture(fShader)); });
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(detachShader, 2) {
|
||
EXJS_UNPACK_ARGV(Future fProgram, Future fShader);
|
||
addToNextBatch([=] { glDetachShader(peekFuture(fProgram), peekFuture(fShader)); });
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(getAttachedShaders, 1) {
|
||
EXJS_UNPACK_ARGV(Future fProgram);
|
||
|
||
GLint count;
|
||
std::vector<GLuint> glResults;
|
||
addBlockingToNextBatch([&] {
|
||
GLuint program = peekFuture(fProgram);
|
||
glGetProgramiv(program, GL_ATTACHED_SHADERS, &count);
|
||
glResults.resize(count);
|
||
glGetAttachedShaders(program, count, nullptr, glResults.data());
|
||
});
|
||
|
||
JSValueRef jsResults[count];
|
||
for (auto i = 0; i < count; ++i) {
|
||
Future future = 0;
|
||
for (const auto &pair : futures) {
|
||
if (pair.second == glResults[i]) {
|
||
future = pair.first;
|
||
}
|
||
}
|
||
if (future == 0) {
|
||
throw new std::runtime_error("EXGL: Internal error: couldn't find Future "
|
||
"associated with shader in getAttachedShaders()!");
|
||
}
|
||
jsResults[i] = JSValueMakeNumber(jsCtx, future);
|
||
}
|
||
return JSObjectMakeArray(jsCtx, count, jsResults, nullptr);
|
||
}
|
||
|
||
_WRAP_METHOD(getProgramParameter, 2) {
|
||
EXJS_UNPACK_ARGV(Future fProgram, GLenum pname);
|
||
GLint glResult;
|
||
addBlockingToNextBatch([&] { glGetProgramiv(peekFuture(fProgram), pname, &glResult); });
|
||
if (pname == GL_DELETE_STATUS || pname == GL_LINK_STATUS || pname == GL_VALIDATE_STATUS) {
|
||
return JSValueMakeBoolean(jsCtx, glResult);
|
||
} else {
|
||
return JSValueMakeNumber(jsCtx, glResult);
|
||
}
|
||
}
|
||
|
||
_WRAP_METHOD(getShaderParameter, 2) {
|
||
EXJS_UNPACK_ARGV(Future fShader, GLenum pname);
|
||
GLint glResult;
|
||
addBlockingToNextBatch([&] { glGetShaderiv(peekFuture(fShader), pname, &glResult); });
|
||
if (pname == GL_DELETE_STATUS || pname == GL_COMPILE_STATUS) {
|
||
return JSValueMakeBoolean(jsCtx, glResult);
|
||
} else {
|
||
return JSValueMakeNumber(jsCtx, glResult);
|
||
}
|
||
}
|
||
|
||
_WRAP_METHOD(getShaderPrecisionFormat, 2) {
|
||
EXJS_UNPACK_ARGV(GLenum shaderType, GLenum precisionType);
|
||
|
||
GLint range[2], precision;
|
||
addBlockingToNextBatch([&] {
|
||
glGetShaderPrecisionFormat(shaderType, precisionType, range, &precision);
|
||
});
|
||
|
||
JSObjectRef jsResult = JSObjectMake(jsCtx, nullptr, nullptr);
|
||
EXJSObjectSetValueWithUTF8CStringName(jsCtx, jsResult, "rangeMin",
|
||
JSValueMakeNumber(jsCtx, range[0]));
|
||
EXJSObjectSetValueWithUTF8CStringName(jsCtx, jsResult, "rangeMax",
|
||
JSValueMakeNumber(jsCtx, range[1]));
|
||
EXJSObjectSetValueWithUTF8CStringName(jsCtx, jsResult, "precision",
|
||
JSValueMakeNumber(jsCtx, precision));
|
||
return jsResult;
|
||
}
|
||
|
||
template<typename F, typename G>
|
||
inline JSValueRef getShaderOrProgramStr(JSContextRef jsCtx, const JSValueRef jsArgv[],
|
||
F &&glGetLengthParam, GLenum glLengthParam, G &&glGetStr) {
|
||
EXJS_UNPACK_ARGV(Future fObj);
|
||
GLint length;
|
||
std::string str;
|
||
addBlockingToNextBatch([&] {
|
||
GLuint obj = peekFuture(fObj);
|
||
glGetLengthParam(obj, glLengthParam, &length);
|
||
str.resize(length);
|
||
glGetStr(obj, length, nullptr, &str[0]);
|
||
});
|
||
return EXJSValueMakeStringFromUTF8CString(jsCtx, str.c_str());
|
||
}
|
||
|
||
_WRAP_METHOD(getProgramInfoLog, 1) {
|
||
return getShaderOrProgramStr(jsCtx, jsArgv,
|
||
glGetProgramiv, GL_INFO_LOG_LENGTH,
|
||
glGetProgramInfoLog);
|
||
}
|
||
|
||
_WRAP_METHOD(getShaderInfoLog, 1) {
|
||
return getShaderOrProgramStr(jsCtx, jsArgv,
|
||
glGetShaderiv, GL_INFO_LOG_LENGTH,
|
||
glGetShaderInfoLog);
|
||
}
|
||
|
||
_WRAP_METHOD(getShaderSource, 1) {
|
||
return getShaderOrProgramStr(jsCtx, jsArgv,
|
||
glGetShaderiv, GL_SHADER_SOURCE_LENGTH,
|
||
glGetShaderSource);
|
||
}
|
||
|
||
_WRAP_METHOD_IS_OBJECT(Program)
|
||
|
||
_WRAP_METHOD_IS_OBJECT(Shader)
|
||
|
||
_WRAP_METHOD(linkProgram, 1) {
|
||
EXJS_UNPACK_ARGV(Future fProgram);
|
||
addToNextBatch([=] { glLinkProgram(peekFuture(fProgram)); });
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(shaderSource, 2) {
|
||
EXJS_UNPACK_ARGV(Future fShader);
|
||
auto str = jsValueToSharedStr(jsCtx, jsArgv[1]);
|
||
addToNextBatch([=] {
|
||
char *pstr = str.get();
|
||
glShaderSource(peekFuture(fShader), 1, (const char **) &pstr, nullptr);
|
||
});
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(useProgram, 1) {
|
||
if (JSValueIsNull(jsCtx, jsArgv[0])) {
|
||
addToNextBatch(std::bind(glUseProgram, 0));
|
||
} else {
|
||
EXJS_UNPACK_ARGV(Future fProgram);
|
||
addToNextBatch([=] { glUseProgram(peekFuture(fProgram)); });
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(validateProgram, 1) {
|
||
EXJS_UNPACK_ARGV(Future fProgram);
|
||
addToNextBatch([=] { glValidateProgram(peekFuture(fProgram)); });
|
||
return nullptr;
|
||
}
|
||
|
||
|
||
// Uniforms and attributes
|
||
// -----------------------
|
||
|
||
_WRAP_METHOD_SIMPLE(disableVertexAttribArray, glDisableVertexAttribArray, index)
|
||
|
||
_WRAP_METHOD_SIMPLE(enableVertexAttribArray, glEnableVertexAttribArray, index)
|
||
|
||
template<typename F>
|
||
inline JSValueRef getActiveInfo(JSContextRef jsCtx, const JSValueRef jsArgv[],
|
||
GLenum lengthParam, F &&glFunc) {
|
||
if (JSValueIsNull(jsCtx, jsArgv[0])) {
|
||
return JSValueMakeNull(jsCtx);
|
||
}
|
||
|
||
EXJS_UNPACK_ARGV(Future fProgram, GLuint index);
|
||
|
||
GLsizei length;
|
||
GLint size;
|
||
GLenum type;
|
||
std::string name;
|
||
GLint maxNameLength;
|
||
addBlockingToNextBatch([&] {
|
||
GLuint program = peekFuture(fProgram);
|
||
glGetProgramiv(program, lengthParam, &maxNameLength);
|
||
name.resize(maxNameLength);
|
||
glFunc(program, index, maxNameLength, &length, &size, &type, &name[0]);
|
||
});
|
||
|
||
if (strlen(name.c_str()) == 0) { // name.length() may be larger
|
||
return JSValueMakeNull(jsCtx);
|
||
}
|
||
|
||
JSObjectRef jsResult = JSObjectMake(jsCtx, nullptr, nullptr);
|
||
EXJSObjectSetValueWithUTF8CStringName(jsCtx, jsResult, "name",
|
||
EXJSValueMakeStringFromUTF8CString(jsCtx, name.c_str()));
|
||
EXJSObjectSetValueWithUTF8CStringName(jsCtx, jsResult, "size", JSValueMakeNumber(jsCtx, size));
|
||
EXJSObjectSetValueWithUTF8CStringName(jsCtx, jsResult, "type", JSValueMakeNumber(jsCtx, type));
|
||
return jsResult;
|
||
}
|
||
|
||
_WRAP_METHOD(getActiveAttrib, 2) {
|
||
return getActiveInfo(jsCtx, jsArgv, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, glGetActiveAttrib);
|
||
}
|
||
|
||
_WRAP_METHOD(getActiveUniform, 2) {
|
||
return getActiveInfo(jsCtx, jsArgv, GL_ACTIVE_UNIFORM_MAX_LENGTH, glGetActiveUniform);
|
||
}
|
||
|
||
_WRAP_METHOD(getAttribLocation, 2) {
|
||
EXJS_UNPACK_ARGV(Future fProgram);
|
||
auto name = jsValueToSharedStr(jsCtx, jsArgv[1]);
|
||
GLint location;
|
||
addBlockingToNextBatch([&] {
|
||
location = glGetAttribLocation(peekFuture(fProgram), name.get());
|
||
});
|
||
return JSValueMakeNumber(jsCtx, location);
|
||
}
|
||
|
||
_WRAP_METHOD_UNIMPL(getUniform)
|
||
|
||
_WRAP_METHOD(getUniformLocation, 2) {
|
||
EXJS_UNPACK_ARGV(Future fProgram);
|
||
auto name = jsValueToSharedStr(jsCtx, jsArgv[1]);
|
||
GLint location;
|
||
addBlockingToNextBatch([&] {
|
||
location = glGetUniformLocation(peekFuture(fProgram), name.get());
|
||
});
|
||
return location == -1 ? JSValueMakeNull(jsCtx) : JSValueMakeNumber(jsCtx, location);
|
||
}
|
||
|
||
_WRAP_METHOD_UNIMPL(getVertexAttrib)
|
||
|
||
_WRAP_METHOD_UNIMPL(getVertexAttribOffset)
|
||
|
||
_WRAP_METHOD_SIMPLE(uniform1f, glUniform1f, uniform, x)
|
||
_WRAP_METHOD_SIMPLE(uniform2f, glUniform2f, uniform, x, y)
|
||
_WRAP_METHOD_SIMPLE(uniform3f, glUniform3f, uniform, x, y, z)
|
||
_WRAP_METHOD_SIMPLE(uniform4f, glUniform4f, uniform, x, y, z, w)
|
||
_WRAP_METHOD_SIMPLE(uniform1i, glUniform1i, uniform, x)
|
||
_WRAP_METHOD_SIMPLE(uniform2i, glUniform2i, uniform, x, y)
|
||
_WRAP_METHOD_SIMPLE(uniform3i, glUniform3i, uniform, x, y, z)
|
||
_WRAP_METHOD_SIMPLE(uniform4i, glUniform4i, uniform, x, y, z, w)
|
||
|
||
#define _WRAP_METHOD_UNIFORM_V(suffix, dim, Type) \
|
||
_WRAP_METHOD(uniform##suffix, 2) { \
|
||
GLuint uniform = EXJSValueToNumberFast(jsCtx, jsArgv[0]); \
|
||
size_t bytes; \
|
||
auto data = jsValueToSharedArray(jsCtx, jsArgv[1], &bytes); \
|
||
GLsizei count = (GLsizei) bytes / sizeof(Type); \
|
||
addToNextBatch([=] { \
|
||
glUniform##suffix(uniform, count / dim, (Type *) data.get()); \
|
||
}); \
|
||
return nullptr; \
|
||
}
|
||
_WRAP_METHOD_UNIFORM_V(1fv, 1, GLfloat)
|
||
_WRAP_METHOD_UNIFORM_V(2fv, 2, GLfloat)
|
||
_WRAP_METHOD_UNIFORM_V(3fv, 3, GLfloat)
|
||
_WRAP_METHOD_UNIFORM_V(4fv, 4, GLfloat)
|
||
_WRAP_METHOD_UNIFORM_V(1iv, 1, GLint)
|
||
_WRAP_METHOD_UNIFORM_V(2iv, 2, GLint)
|
||
_WRAP_METHOD_UNIFORM_V(3iv, 3, GLint)
|
||
_WRAP_METHOD_UNIFORM_V(4iv, 4, GLint)
|
||
#undef _WRAP_METHOD_UNIFORM_V
|
||
|
||
#define _WRAP_METHOD_UNIFORM_MATRIX(suffix, dim) \
|
||
_WRAP_METHOD(uniformMatrix##suffix, 3) { \
|
||
GLuint uniform = EXJSValueToNumberFast(jsCtx, jsArgv[0]); \
|
||
GLboolean transpose = JSValueToBoolean(jsCtx, jsArgv[1]); \
|
||
size_t bytes; \
|
||
auto data = jsValueToSharedArray(jsCtx, jsArgv[2], &bytes); \
|
||
GLsizei count = (GLsizei) bytes / sizeof(GLfloat); \
|
||
addToNextBatch([=] { \
|
||
glUniformMatrix##suffix(uniform, count / dim, transpose, (GLfloat *) data.get()); \
|
||
}); \
|
||
return nullptr; \
|
||
}
|
||
_WRAP_METHOD_UNIFORM_MATRIX(2fv, 4)
|
||
_WRAP_METHOD_UNIFORM_MATRIX(3fv, 9)
|
||
_WRAP_METHOD_UNIFORM_MATRIX(4fv, 16)
|
||
#undef _WRAP_METHOD_UNIFORM_MATRIX
|
||
|
||
#define _WRAP_METHOD_VERTEX_ATTRIB_V(suffix, dim) \
|
||
_WRAP_METHOD(vertexAttrib##suffix, 2) { \
|
||
GLuint index = EXJSValueToNumberFast(jsCtx, jsArgv[0]); \
|
||
auto data = jsValueToSharedArray(jsCtx, jsArgv[1], nullptr); \
|
||
addToNextBatch([=] { glVertexAttrib##suffix(index, (GLfloat *) data.get());}); \
|
||
return nullptr; \
|
||
}
|
||
_WRAP_METHOD_VERTEX_ATTRIB_V(1fv, 1)
|
||
_WRAP_METHOD_VERTEX_ATTRIB_V(2fv, 1)
|
||
_WRAP_METHOD_VERTEX_ATTRIB_V(3fv, 1)
|
||
_WRAP_METHOD_VERTEX_ATTRIB_V(4fv, 1)
|
||
#undef _WRAP_METHOD_VERTEX_ATTRIB_V
|
||
|
||
_WRAP_METHOD_SIMPLE(vertexAttrib1f, glVertexAttrib1f, index, x)
|
||
_WRAP_METHOD_SIMPLE(vertexAttrib2f, glVertexAttrib2f, index, x, y)
|
||
_WRAP_METHOD_SIMPLE(vertexAttrib3f, glVertexAttrib3f, index, x, y, z)
|
||
_WRAP_METHOD_SIMPLE(vertexAttrib4f, glVertexAttrib4f, index, x, y, z, w)
|
||
|
||
_WRAP_METHOD(vertexAttribPointer, 6) {
|
||
EXJS_UNPACK_ARGV(GLuint index, GLuint itemSize, GLenum type,
|
||
GLboolean normalized, GLsizei stride, GLint offset);
|
||
addToNextBatch(std::bind(glVertexAttribPointer, index, itemSize, type,
|
||
normalized, stride, bufferOffset(offset)));
|
||
return nullptr;
|
||
}
|
||
|
||
|
||
// Drawing buffers
|
||
// ---------------
|
||
|
||
_WRAP_METHOD_SIMPLE(clear, glClear, mask)
|
||
|
||
_WRAP_METHOD_SIMPLE(drawArrays, glDrawArrays, mode, first, count)
|
||
|
||
_WRAP_METHOD(drawElements, 4) {
|
||
EXJS_UNPACK_ARGV(GLenum mode, GLsizei count, GLenum type, GLint offset);
|
||
addToNextBatch(std::bind(glDrawElements, mode, count, type, bufferOffset(offset)));
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(finish, 0) {
|
||
addToNextBatch(glFinish);
|
||
return nullptr;
|
||
}
|
||
|
||
_WRAP_METHOD(flush, 0) {
|
||
addToNextBatch(glFlush);
|
||
return nullptr;
|
||
}
|
||
|
||
|
||
// Extensions
|
||
// ----------
|
||
|
||
_WRAP_METHOD(getSupportedExtensions, 0) {
|
||
return JSObjectMakeArray(jsCtx, 0, NULL, NULL);
|
||
}
|
||
|
||
_WRAP_METHOD(getExtension, 1) {
|
||
return JSValueMakeNull(jsCtx);
|
||
}
|
||
|
||
|
||
// Expo extensions
|
||
// -------------------
|
||
|
||
_WRAP_METHOD(endFrameEXP, 0) {
|
||
endNextBatch();
|
||
return nullptr;
|
||
}
|
||
|
||
|
||
#undef _WRAP_METHOD_SIMPLE_UNPACK
|
||
#undef _WRAP_METHOD_SIMPLE
|
||
#undef _WRAP_METHOD_UNIMPL
|
||
#undef _WRAP_METHOD
|
||
|
||
|
||
void installMethods(JSContextRef jsCtx) {
|
||
#define _INSTALL_METHOD(name) \
|
||
EXJSObjectSetFunctionWithUTF8CStringName(jsCtx, jsGl, #name, \
|
||
&EXGLContext::exglNativeStatic_##name)
|
||
|
||
// This listing follows the order in
|
||
// https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext
|
||
|
||
// The WebGL context
|
||
_INSTALL_METHOD(getContextAttributes);
|
||
_INSTALL_METHOD(isContextLost);
|
||
|
||
// Viewing and clipping
|
||
_INSTALL_METHOD(scissor);
|
||
_INSTALL_METHOD(viewport);
|
||
|
||
// State information
|
||
_INSTALL_METHOD(activeTexture);
|
||
_INSTALL_METHOD(blendColor);
|
||
_INSTALL_METHOD(blendEquation);
|
||
_INSTALL_METHOD(blendEquationSeparate);
|
||
_INSTALL_METHOD(blendFunc);
|
||
_INSTALL_METHOD(blendFuncSeparate);
|
||
_INSTALL_METHOD(clearColor);
|
||
_INSTALL_METHOD(clearDepth);
|
||
_INSTALL_METHOD(clearStencil);
|
||
_INSTALL_METHOD(colorMask);
|
||
_INSTALL_METHOD(cullFace);
|
||
_INSTALL_METHOD(depthFunc);
|
||
_INSTALL_METHOD(depthMask);
|
||
_INSTALL_METHOD(depthRange);
|
||
_INSTALL_METHOD(disable);
|
||
_INSTALL_METHOD(enable);
|
||
_INSTALL_METHOD(frontFace);
|
||
_INSTALL_METHOD(getParameter);
|
||
_INSTALL_METHOD(getError);
|
||
_INSTALL_METHOD(hint);
|
||
_INSTALL_METHOD(isEnabled);
|
||
_INSTALL_METHOD(lineWidth);
|
||
_INSTALL_METHOD(pixelStorei);
|
||
_INSTALL_METHOD(polygonOffset);
|
||
_INSTALL_METHOD(sampleCoverage);
|
||
_INSTALL_METHOD(stencilFunc);
|
||
_INSTALL_METHOD(stencilFuncSeparate);
|
||
_INSTALL_METHOD(stencilMask);
|
||
_INSTALL_METHOD(stencilMaskSeparate);
|
||
_INSTALL_METHOD(stencilOp);
|
||
_INSTALL_METHOD(stencilOpSeparate);
|
||
|
||
// Buffers
|
||
_INSTALL_METHOD(bindBuffer);
|
||
_INSTALL_METHOD(bufferData);
|
||
_INSTALL_METHOD(bufferSubData);
|
||
_INSTALL_METHOD(createBuffer);
|
||
_INSTALL_METHOD(deleteBuffer);
|
||
_INSTALL_METHOD(getBufferParameter);
|
||
_INSTALL_METHOD(isBuffer);
|
||
|
||
// Framebuffers
|
||
_INSTALL_METHOD(bindFramebuffer);
|
||
_INSTALL_METHOD(checkFramebufferStatus);
|
||
_INSTALL_METHOD(createFramebuffer);
|
||
_INSTALL_METHOD(deleteFramebuffer);
|
||
_INSTALL_METHOD(framebufferRenderbuffer);
|
||
_INSTALL_METHOD(framebufferTexture2D);
|
||
_INSTALL_METHOD(getFramebufferAttachmentParameter);
|
||
_INSTALL_METHOD(isFramebuffer);
|
||
_INSTALL_METHOD(readPixels);
|
||
|
||
// Renderbuffers
|
||
_INSTALL_METHOD(bindRenderbuffer);
|
||
_INSTALL_METHOD(createRenderbuffer);
|
||
_INSTALL_METHOD(deleteRenderbuffer);
|
||
_INSTALL_METHOD(getRenderbufferParameter);
|
||
_INSTALL_METHOD(isRenderbuffer);
|
||
_INSTALL_METHOD(renderbufferStorage);
|
||
|
||
// Textures
|
||
_INSTALL_METHOD(bindTexture);
|
||
_INSTALL_METHOD(compressedTexImage2D);
|
||
_INSTALL_METHOD(compressedTexSubImage2D);
|
||
_INSTALL_METHOD(copyTexImage2D);
|
||
_INSTALL_METHOD(copyTexSubImage2D);
|
||
_INSTALL_METHOD(createTexture);
|
||
_INSTALL_METHOD(deleteTexture);
|
||
_INSTALL_METHOD(generateMipmap);
|
||
_INSTALL_METHOD(getTexParameter);
|
||
_INSTALL_METHOD(isTexture);
|
||
_INSTALL_METHOD(texImage2D);
|
||
_INSTALL_METHOD(texSubImage2D);
|
||
_INSTALL_METHOD(texParameterf);
|
||
_INSTALL_METHOD(texParameteri);
|
||
|
||
// Programs and shaders
|
||
_INSTALL_METHOD(attachShader);
|
||
_INSTALL_METHOD(bindAttribLocation);
|
||
_INSTALL_METHOD(compileShader);
|
||
_INSTALL_METHOD(createProgram);
|
||
_INSTALL_METHOD(createShader);
|
||
_INSTALL_METHOD(deleteProgram);
|
||
_INSTALL_METHOD(deleteShader);
|
||
_INSTALL_METHOD(detachShader);
|
||
_INSTALL_METHOD(getAttachedShaders);
|
||
_INSTALL_METHOD(getProgramParameter);
|
||
_INSTALL_METHOD(getProgramInfoLog);
|
||
_INSTALL_METHOD(getShaderParameter);
|
||
_INSTALL_METHOD(getShaderPrecisionFormat);
|
||
_INSTALL_METHOD(getShaderInfoLog);
|
||
_INSTALL_METHOD(getShaderSource);
|
||
_INSTALL_METHOD(isProgram);
|
||
_INSTALL_METHOD(isShader);
|
||
_INSTALL_METHOD(linkProgram);
|
||
_INSTALL_METHOD(shaderSource);
|
||
_INSTALL_METHOD(useProgram);
|
||
_INSTALL_METHOD(validateProgram);
|
||
|
||
// Uniforms and attributes
|
||
_INSTALL_METHOD(disableVertexAttribArray);
|
||
_INSTALL_METHOD(enableVertexAttribArray);
|
||
_INSTALL_METHOD(getActiveAttrib);
|
||
_INSTALL_METHOD(getActiveUniform);
|
||
_INSTALL_METHOD(getAttribLocation);
|
||
_INSTALL_METHOD(getUniform);
|
||
_INSTALL_METHOD(getUniformLocation);
|
||
_INSTALL_METHOD(getVertexAttrib);
|
||
_INSTALL_METHOD(getVertexAttribOffset);
|
||
_INSTALL_METHOD(uniform1f);
|
||
_INSTALL_METHOD(uniform1fv);
|
||
_INSTALL_METHOD(uniform1i);
|
||
_INSTALL_METHOD(uniform1iv);
|
||
_INSTALL_METHOD(uniform2f);
|
||
_INSTALL_METHOD(uniform2fv);
|
||
_INSTALL_METHOD(uniform2i);
|
||
_INSTALL_METHOD(uniform2iv);
|
||
_INSTALL_METHOD(uniform3f);
|
||
_INSTALL_METHOD(uniform3fv);
|
||
_INSTALL_METHOD(uniform3i);
|
||
_INSTALL_METHOD(uniform3iv);
|
||
_INSTALL_METHOD(uniform4f);
|
||
_INSTALL_METHOD(uniform4fv);
|
||
_INSTALL_METHOD(uniform4i);
|
||
_INSTALL_METHOD(uniform4iv);
|
||
_INSTALL_METHOD(uniformMatrix2fv);
|
||
_INSTALL_METHOD(uniformMatrix3fv);
|
||
_INSTALL_METHOD(uniformMatrix4fv);
|
||
_INSTALL_METHOD(vertexAttrib1f);
|
||
_INSTALL_METHOD(vertexAttrib1fv);
|
||
_INSTALL_METHOD(vertexAttrib2f);
|
||
_INSTALL_METHOD(vertexAttrib2fv);
|
||
_INSTALL_METHOD(vertexAttrib3f);
|
||
_INSTALL_METHOD(vertexAttrib3fv);
|
||
_INSTALL_METHOD(vertexAttrib4f);
|
||
_INSTALL_METHOD(vertexAttrib4fv);
|
||
_INSTALL_METHOD(vertexAttribPointer);
|
||
|
||
// Drawing buffers
|
||
_INSTALL_METHOD(clear);
|
||
_INSTALL_METHOD(drawArrays);
|
||
_INSTALL_METHOD(drawElements);
|
||
_INSTALL_METHOD(finish);
|
||
_INSTALL_METHOD(flush);
|
||
|
||
// Extensions
|
||
_INSTALL_METHOD(getSupportedExtensions);
|
||
_INSTALL_METHOD(getExtension);
|
||
|
||
// Expo extensions
|
||
_INSTALL_METHOD(endFrameEXP);
|
||
|
||
#undef _INSTALL_METHOD
|
||
}
|
||
|
||
|
||
void installConstants(JSContextRef jsCtx) {
|
||
#define _INSTALL_CONSTANT(name) \
|
||
EXJSObjectSetValueWithUTF8CStringName(jsCtx, jsGl, #name, \
|
||
JSValueMakeNumber(jsCtx, GL_ ## name))
|
||
|
||
_INSTALL_CONSTANT(ACTIVE_ATTRIBUTES); //35721
|
||
// _INSTALL_CONSTANT(ACTIVE_ATTRIBUTE_MAX_LENGTH); //35722
|
||
_INSTALL_CONSTANT(ACTIVE_TEXTURE); //34016
|
||
_INSTALL_CONSTANT(ACTIVE_UNIFORMS); //35718
|
||
// _INSTALL_CONSTANT(ACTIVE_UNIFORM_MAX_LENGTH); //35719
|
||
_INSTALL_CONSTANT(ALIASED_LINE_WIDTH_RANGE); //33902
|
||
_INSTALL_CONSTANT(ALIASED_POINT_SIZE_RANGE); //33901
|
||
_INSTALL_CONSTANT(ALPHA); //6406
|
||
_INSTALL_CONSTANT(ALPHA_BITS); //3413
|
||
_INSTALL_CONSTANT(ALWAYS); //519
|
||
_INSTALL_CONSTANT(ARRAY_BUFFER); //34962
|
||
_INSTALL_CONSTANT(ARRAY_BUFFER_BINDING); //34964
|
||
_INSTALL_CONSTANT(ATTACHED_SHADERS); //35717
|
||
_INSTALL_CONSTANT(BACK); //1029
|
||
_INSTALL_CONSTANT(BLEND); //3042
|
||
_INSTALL_CONSTANT(BLEND_COLOR); //32773
|
||
_INSTALL_CONSTANT(BLEND_DST_ALPHA); //32970
|
||
_INSTALL_CONSTANT(BLEND_DST_RGB); //32968
|
||
_INSTALL_CONSTANT(BLEND_EQUATION); //32777
|
||
_INSTALL_CONSTANT(BLEND_EQUATION_ALPHA); //34877
|
||
_INSTALL_CONSTANT(BLEND_EQUATION_RGB); //32777
|
||
_INSTALL_CONSTANT(BLEND_SRC_ALPHA); //32971
|
||
_INSTALL_CONSTANT(BLEND_SRC_RGB); //32969
|
||
_INSTALL_CONSTANT(BLUE_BITS); //3412
|
||
_INSTALL_CONSTANT(BOOL); //35670
|
||
_INSTALL_CONSTANT(BOOL_VEC2); //35671
|
||
_INSTALL_CONSTANT(BOOL_VEC3); //35672
|
||
_INSTALL_CONSTANT(BOOL_VEC4); //35673
|
||
_INSTALL_CONSTANT(BROWSER_DEFAULT_WEBGL); //37444
|
||
_INSTALL_CONSTANT(BUFFER_SIZE); //34660
|
||
_INSTALL_CONSTANT(BUFFER_USAGE); //34661
|
||
_INSTALL_CONSTANT(BYTE); //5120
|
||
_INSTALL_CONSTANT(CCW); //2305
|
||
_INSTALL_CONSTANT(CLAMP_TO_EDGE); //33071
|
||
_INSTALL_CONSTANT(COLOR_ATTACHMENT0); //36064
|
||
_INSTALL_CONSTANT(COLOR_BUFFER_BIT); //16384
|
||
_INSTALL_CONSTANT(COLOR_CLEAR_VALUE); //3106
|
||
_INSTALL_CONSTANT(COLOR_WRITEMASK); //3107
|
||
_INSTALL_CONSTANT(COMPILE_STATUS); //35713
|
||
_INSTALL_CONSTANT(COMPRESSED_TEXTURE_FORMATS); //34467
|
||
_INSTALL_CONSTANT(CONSTANT_ALPHA); //32771
|
||
_INSTALL_CONSTANT(CONSTANT_COLOR); //32769
|
||
_INSTALL_CONSTANT(CONTEXT_LOST_WEBGL); //37442
|
||
_INSTALL_CONSTANT(CULL_FACE); //2884
|
||
_INSTALL_CONSTANT(CULL_FACE_MODE); //2885
|
||
_INSTALL_CONSTANT(CURRENT_PROGRAM); //35725
|
||
_INSTALL_CONSTANT(CURRENT_VERTEX_ATTRIB); //34342
|
||
_INSTALL_CONSTANT(CW); //2304
|
||
_INSTALL_CONSTANT(DECR); //7683
|
||
_INSTALL_CONSTANT(DECR_WRAP); //34056
|
||
_INSTALL_CONSTANT(DELETE_STATUS); //35712
|
||
_INSTALL_CONSTANT(DEPTH_ATTACHMENT); //36096
|
||
_INSTALL_CONSTANT(DEPTH_BITS); //3414
|
||
_INSTALL_CONSTANT(DEPTH_BUFFER_BIT); //256
|
||
_INSTALL_CONSTANT(DEPTH_CLEAR_VALUE); //2931
|
||
_INSTALL_CONSTANT(DEPTH_COMPONENT); //6402
|
||
_INSTALL_CONSTANT(DEPTH_COMPONENT16); //33189
|
||
_INSTALL_CONSTANT(DEPTH_FUNC); //2932
|
||
_INSTALL_CONSTANT(DEPTH_RANGE); //2928
|
||
_INSTALL_CONSTANT(DEPTH_STENCIL); //34041
|
||
_INSTALL_CONSTANT(DEPTH_STENCIL_ATTACHMENT); //33306
|
||
_INSTALL_CONSTANT(DEPTH_TEST); //2929
|
||
_INSTALL_CONSTANT(DEPTH_WRITEMASK); //2930
|
||
_INSTALL_CONSTANT(DITHER); //3024
|
||
_INSTALL_CONSTANT(DONT_CARE); //4352
|
||
_INSTALL_CONSTANT(DST_ALPHA); //772
|
||
_INSTALL_CONSTANT(DST_COLOR); //774
|
||
_INSTALL_CONSTANT(DYNAMIC_DRAW); //35048
|
||
_INSTALL_CONSTANT(ELEMENT_ARRAY_BUFFER); //34963
|
||
_INSTALL_CONSTANT(ELEMENT_ARRAY_BUFFER_BINDING); //34965
|
||
_INSTALL_CONSTANT(EQUAL); //514
|
||
// _INSTALL_CONSTANT(FALSE); //0
|
||
_INSTALL_CONSTANT(FASTEST); //4353
|
||
_INSTALL_CONSTANT(FLOAT); //5126
|
||
_INSTALL_CONSTANT(FLOAT_MAT2); //35674
|
||
_INSTALL_CONSTANT(FLOAT_MAT3); //35675
|
||
_INSTALL_CONSTANT(FLOAT_MAT4); //35676
|
||
_INSTALL_CONSTANT(FLOAT_VEC2); //35664
|
||
_INSTALL_CONSTANT(FLOAT_VEC3); //35665
|
||
_INSTALL_CONSTANT(FLOAT_VEC4); //35666
|
||
_INSTALL_CONSTANT(FRAGMENT_SHADER); //35632
|
||
_INSTALL_CONSTANT(FRAMEBUFFER); //36160
|
||
_INSTALL_CONSTANT(FRAMEBUFFER_ATTACHMENT_OBJECT_NAME); //36049
|
||
_INSTALL_CONSTANT(FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE); //36048
|
||
_INSTALL_CONSTANT(FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE); //36051
|
||
_INSTALL_CONSTANT(FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL); //36050
|
||
_INSTALL_CONSTANT(FRAMEBUFFER_BINDING); //36006
|
||
_INSTALL_CONSTANT(FRAMEBUFFER_COMPLETE); //36053
|
||
_INSTALL_CONSTANT(FRAMEBUFFER_INCOMPLETE_ATTACHMENT); //36054
|
||
_INSTALL_CONSTANT(FRAMEBUFFER_INCOMPLETE_DIMENSIONS); //36057
|
||
_INSTALL_CONSTANT(FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT); //36055
|
||
_INSTALL_CONSTANT(FRAMEBUFFER_UNSUPPORTED); //36061
|
||
_INSTALL_CONSTANT(FRONT); //1028
|
||
_INSTALL_CONSTANT(FRONT_AND_BACK); //1032
|
||
_INSTALL_CONSTANT(FRONT_FACE); //2886
|
||
_INSTALL_CONSTANT(FUNC_ADD); //32774
|
||
_INSTALL_CONSTANT(FUNC_REVERSE_SUBTRACT); //32779
|
||
_INSTALL_CONSTANT(FUNC_SUBTRACT); //32778
|
||
_INSTALL_CONSTANT(GENERATE_MIPMAP_HINT); //33170
|
||
_INSTALL_CONSTANT(GEQUAL); //518
|
||
_INSTALL_CONSTANT(GREATER); //516
|
||
_INSTALL_CONSTANT(GREEN_BITS); //3411
|
||
_INSTALL_CONSTANT(HIGH_FLOAT); //36338
|
||
_INSTALL_CONSTANT(HIGH_INT); //36341
|
||
_INSTALL_CONSTANT(IMPLEMENTATION_COLOR_READ_TYPE); //35738
|
||
_INSTALL_CONSTANT(IMPLEMENTATION_COLOR_READ_FORMAT); //35739
|
||
_INSTALL_CONSTANT(INCR); //7682
|
||
_INSTALL_CONSTANT(INCR_WRAP); //34055
|
||
// _INSTALL_CONSTANT(INFO_LOG_LENGTH); //35716
|
||
_INSTALL_CONSTANT(INT); //5124
|
||
_INSTALL_CONSTANT(INT_VEC2); //35667
|
||
_INSTALL_CONSTANT(INT_VEC3); //35668
|
||
_INSTALL_CONSTANT(INT_VEC4); //35669
|
||
_INSTALL_CONSTANT(INVALID_ENUM); //1280
|
||
_INSTALL_CONSTANT(INVALID_FRAMEBUFFER_OPERATION); //1286
|
||
_INSTALL_CONSTANT(INVALID_OPERATION); //1282
|
||
_INSTALL_CONSTANT(INVALID_VALUE); //1281
|
||
_INSTALL_CONSTANT(INVERT); //5386
|
||
_INSTALL_CONSTANT(KEEP); //7680
|
||
_INSTALL_CONSTANT(LEQUAL); //515
|
||
_INSTALL_CONSTANT(LESS); //513
|
||
_INSTALL_CONSTANT(LINEAR); //9729
|
||
_INSTALL_CONSTANT(LINEAR_MIPMAP_LINEAR); //9987
|
||
_INSTALL_CONSTANT(LINEAR_MIPMAP_NEAREST); //9985
|
||
_INSTALL_CONSTANT(LINES); //1
|
||
_INSTALL_CONSTANT(LINE_LOOP); //2
|
||
_INSTALL_CONSTANT(LINE_STRIP); //3
|
||
_INSTALL_CONSTANT(LINE_WIDTH); //2849
|
||
_INSTALL_CONSTANT(LINK_STATUS); //35714
|
||
_INSTALL_CONSTANT(LOW_FLOAT); //36336
|
||
_INSTALL_CONSTANT(LOW_INT); //36339
|
||
_INSTALL_CONSTANT(LUMINANCE); //6409
|
||
_INSTALL_CONSTANT(LUMINANCE_ALPHA); //6410
|
||
_INSTALL_CONSTANT(MAX_COMBINED_TEXTURE_IMAGE_UNITS); //35661
|
||
_INSTALL_CONSTANT(MAX_CUBE_MAP_TEXTURE_SIZE); //34076
|
||
_INSTALL_CONSTANT(MAX_FRAGMENT_UNIFORM_VECTORS); //36349
|
||
_INSTALL_CONSTANT(MAX_RENDERBUFFER_SIZE); //34024
|
||
_INSTALL_CONSTANT(MAX_TEXTURE_IMAGE_UNITS); //34930
|
||
_INSTALL_CONSTANT(MAX_TEXTURE_SIZE); //3379
|
||
_INSTALL_CONSTANT(MAX_VARYING_VECTORS); //36348
|
||
_INSTALL_CONSTANT(MAX_VERTEX_ATTRIBS); //34921
|
||
_INSTALL_CONSTANT(MAX_VERTEX_TEXTURE_IMAGE_UNITS); //35660
|
||
_INSTALL_CONSTANT(MAX_VERTEX_UNIFORM_VECTORS); //36347
|
||
_INSTALL_CONSTANT(MAX_VIEWPORT_DIMS); //3386
|
||
_INSTALL_CONSTANT(MEDIUM_FLOAT); //36337
|
||
_INSTALL_CONSTANT(MEDIUM_INT); //36340
|
||
_INSTALL_CONSTANT(MIRRORED_REPEAT); //33648
|
||
_INSTALL_CONSTANT(NEAREST); //9728
|
||
_INSTALL_CONSTANT(NEAREST_MIPMAP_LINEAR); //9986
|
||
_INSTALL_CONSTANT(NEAREST_MIPMAP_NEAREST); //9984
|
||
_INSTALL_CONSTANT(NEVER); //512
|
||
_INSTALL_CONSTANT(NICEST); //4354
|
||
_INSTALL_CONSTANT(NONE); //0
|
||
_INSTALL_CONSTANT(NOTEQUAL); //517
|
||
_INSTALL_CONSTANT(NO_ERROR); //0
|
||
// _INSTALL_CONSTANT(NUM_COMPRESSED_TEXTURE_FORMATS); //34466
|
||
_INSTALL_CONSTANT(ONE); //1
|
||
_INSTALL_CONSTANT(ONE_MINUS_CONSTANT_ALPHA); //32772
|
||
_INSTALL_CONSTANT(ONE_MINUS_CONSTANT_COLOR); //32770
|
||
_INSTALL_CONSTANT(ONE_MINUS_DST_ALPHA); //773
|
||
_INSTALL_CONSTANT(ONE_MINUS_DST_COLOR); //775
|
||
_INSTALL_CONSTANT(ONE_MINUS_SRC_ALPHA); //771
|
||
_INSTALL_CONSTANT(ONE_MINUS_SRC_COLOR); //769
|
||
_INSTALL_CONSTANT(OUT_OF_MEMORY); //1285
|
||
_INSTALL_CONSTANT(PACK_ALIGNMENT); //3333
|
||
_INSTALL_CONSTANT(POINTS); //0
|
||
_INSTALL_CONSTANT(POLYGON_OFFSET_FACTOR); //32824
|
||
_INSTALL_CONSTANT(POLYGON_OFFSET_FILL); //32823
|
||
_INSTALL_CONSTANT(POLYGON_OFFSET_UNITS); //10752
|
||
_INSTALL_CONSTANT(RED_BITS); //3410
|
||
_INSTALL_CONSTANT(RENDERBUFFER); //36161
|
||
_INSTALL_CONSTANT(RENDERBUFFER_ALPHA_SIZE); //36179
|
||
_INSTALL_CONSTANT(RENDERBUFFER_BINDING); //36007
|
||
_INSTALL_CONSTANT(RENDERBUFFER_BLUE_SIZE); //36178
|
||
_INSTALL_CONSTANT(RENDERBUFFER_DEPTH_SIZE); //36180
|
||
_INSTALL_CONSTANT(RENDERBUFFER_GREEN_SIZE); //36177
|
||
_INSTALL_CONSTANT(RENDERBUFFER_HEIGHT); //36163
|
||
_INSTALL_CONSTANT(RENDERBUFFER_INTERNAL_FORMAT); //36164
|
||
_INSTALL_CONSTANT(RENDERBUFFER_RED_SIZE); //36176
|
||
_INSTALL_CONSTANT(RENDERBUFFER_STENCIL_SIZE); //36181
|
||
_INSTALL_CONSTANT(RENDERBUFFER_WIDTH); //36162
|
||
_INSTALL_CONSTANT(RENDERER); //7937
|
||
_INSTALL_CONSTANT(REPEAT); //10497
|
||
_INSTALL_CONSTANT(REPLACE); //7681
|
||
_INSTALL_CONSTANT(RGB); //6407
|
||
_INSTALL_CONSTANT(RGB5_A1); //32855
|
||
_INSTALL_CONSTANT(RGB565); //36194
|
||
_INSTALL_CONSTANT(RGBA); //6408
|
||
_INSTALL_CONSTANT(RGBA4); //32854
|
||
_INSTALL_CONSTANT(SAMPLER_2D); //35678
|
||
_INSTALL_CONSTANT(SAMPLER_CUBE); //35680
|
||
_INSTALL_CONSTANT(SAMPLES); //32937
|
||
_INSTALL_CONSTANT(SAMPLE_ALPHA_TO_COVERAGE); //32926
|
||
_INSTALL_CONSTANT(SAMPLE_BUFFERS); //32936
|
||
_INSTALL_CONSTANT(SAMPLE_COVERAGE); //32928
|
||
_INSTALL_CONSTANT(SAMPLE_COVERAGE_INVERT); //32939
|
||
_INSTALL_CONSTANT(SAMPLE_COVERAGE_VALUE); //32938
|
||
_INSTALL_CONSTANT(SCISSOR_BOX); //3088
|
||
_INSTALL_CONSTANT(SCISSOR_TEST); //3089
|
||
// _INSTALL_CONSTANT(SHADER_COMPILER); //36346
|
||
// _INSTALL_CONSTANT(SHADER_SOURCE_LENGTH); //35720
|
||
_INSTALL_CONSTANT(SHADER_TYPE); //35663
|
||
_INSTALL_CONSTANT(SHADING_LANGUAGE_VERSION); //35724
|
||
_INSTALL_CONSTANT(SHORT); //5122
|
||
_INSTALL_CONSTANT(SRC_ALPHA); //770
|
||
_INSTALL_CONSTANT(SRC_ALPHA_SATURATE); //776
|
||
_INSTALL_CONSTANT(SRC_COLOR); //768
|
||
_INSTALL_CONSTANT(STATIC_DRAW); //35044
|
||
_INSTALL_CONSTANT(STENCIL_ATTACHMENT); //36128
|
||
_INSTALL_CONSTANT(STENCIL_BACK_FAIL); //34817
|
||
_INSTALL_CONSTANT(STENCIL_BACK_FUNC); //34816
|
||
_INSTALL_CONSTANT(STENCIL_BACK_PASS_DEPTH_FAIL); //34818
|
||
_INSTALL_CONSTANT(STENCIL_BACK_PASS_DEPTH_PASS); //34819
|
||
_INSTALL_CONSTANT(STENCIL_BACK_REF); //36003
|
||
_INSTALL_CONSTANT(STENCIL_BACK_VALUE_MASK); //36004
|
||
_INSTALL_CONSTANT(STENCIL_BACK_WRITEMASK); //36005
|
||
_INSTALL_CONSTANT(STENCIL_BITS); //3415
|
||
_INSTALL_CONSTANT(STENCIL_BUFFER_BIT); //1024
|
||
_INSTALL_CONSTANT(STENCIL_CLEAR_VALUE); //2961
|
||
_INSTALL_CONSTANT(STENCIL_FAIL); //2964
|
||
_INSTALL_CONSTANT(STENCIL_FUNC); //2962
|
||
_INSTALL_CONSTANT(STENCIL_INDEX); //6401
|
||
_INSTALL_CONSTANT(STENCIL_INDEX8); //36168
|
||
_INSTALL_CONSTANT(STENCIL_PASS_DEPTH_FAIL); //2965
|
||
_INSTALL_CONSTANT(STENCIL_PASS_DEPTH_PASS); //2966
|
||
_INSTALL_CONSTANT(STENCIL_REF); //2967
|
||
_INSTALL_CONSTANT(STENCIL_TEST); //2960
|
||
_INSTALL_CONSTANT(STENCIL_VALUE_MASK); //2963
|
||
_INSTALL_CONSTANT(STENCIL_WRITEMASK); //2968
|
||
_INSTALL_CONSTANT(STREAM_DRAW); //35040
|
||
_INSTALL_CONSTANT(SUBPIXEL_BITS); //3408
|
||
_INSTALL_CONSTANT(TEXTURE); //5890
|
||
_INSTALL_CONSTANT(TEXTURE0); //33984
|
||
_INSTALL_CONSTANT(TEXTURE1); //33985
|
||
_INSTALL_CONSTANT(TEXTURE2); //33986
|
||
_INSTALL_CONSTANT(TEXTURE3); //33987
|
||
_INSTALL_CONSTANT(TEXTURE4); //33988
|
||
_INSTALL_CONSTANT(TEXTURE5); //33989
|
||
_INSTALL_CONSTANT(TEXTURE6); //33990
|
||
_INSTALL_CONSTANT(TEXTURE7); //33991
|
||
_INSTALL_CONSTANT(TEXTURE8); //33992
|
||
_INSTALL_CONSTANT(TEXTURE9); //33993
|
||
_INSTALL_CONSTANT(TEXTURE10); //33994
|
||
_INSTALL_CONSTANT(TEXTURE11); //33995
|
||
_INSTALL_CONSTANT(TEXTURE12); //33996
|
||
_INSTALL_CONSTANT(TEXTURE13); //33997
|
||
_INSTALL_CONSTANT(TEXTURE14); //33998
|
||
_INSTALL_CONSTANT(TEXTURE15); //33999
|
||
_INSTALL_CONSTANT(TEXTURE16); //34000
|
||
_INSTALL_CONSTANT(TEXTURE17); //34001
|
||
_INSTALL_CONSTANT(TEXTURE18); //34002
|
||
_INSTALL_CONSTANT(TEXTURE19); //34003
|
||
_INSTALL_CONSTANT(TEXTURE20); //34004
|
||
_INSTALL_CONSTANT(TEXTURE21); //34005
|
||
_INSTALL_CONSTANT(TEXTURE22); //34006
|
||
_INSTALL_CONSTANT(TEXTURE23); //34007
|
||
_INSTALL_CONSTANT(TEXTURE24); //34008
|
||
_INSTALL_CONSTANT(TEXTURE25); //34009
|
||
_INSTALL_CONSTANT(TEXTURE26); //34010
|
||
_INSTALL_CONSTANT(TEXTURE27); //34011
|
||
_INSTALL_CONSTANT(TEXTURE28); //34012
|
||
_INSTALL_CONSTANT(TEXTURE29); //34013
|
||
_INSTALL_CONSTANT(TEXTURE30); //34014
|
||
_INSTALL_CONSTANT(TEXTURE31); //34015
|
||
_INSTALL_CONSTANT(TEXTURE_2D); //3553
|
||
_INSTALL_CONSTANT(TEXTURE_BINDING_2D); //32873
|
||
_INSTALL_CONSTANT(TEXTURE_BINDING_CUBE_MAP); //34068
|
||
_INSTALL_CONSTANT(TEXTURE_CUBE_MAP); //34067
|
||
_INSTALL_CONSTANT(TEXTURE_CUBE_MAP_NEGATIVE_X); //34070
|
||
_INSTALL_CONSTANT(TEXTURE_CUBE_MAP_NEGATIVE_Y); //34072
|
||
_INSTALL_CONSTANT(TEXTURE_CUBE_MAP_NEGATIVE_Z); //34074
|
||
_INSTALL_CONSTANT(TEXTURE_CUBE_MAP_POSITIVE_X); //34069
|
||
_INSTALL_CONSTANT(TEXTURE_CUBE_MAP_POSITIVE_Y); //34071
|
||
_INSTALL_CONSTANT(TEXTURE_CUBE_MAP_POSITIVE_Z); //34073
|
||
_INSTALL_CONSTANT(TEXTURE_MAG_FILTER); //10240
|
||
_INSTALL_CONSTANT(TEXTURE_MIN_FILTER); //10241
|
||
_INSTALL_CONSTANT(TEXTURE_WRAP_S); //10242
|
||
_INSTALL_CONSTANT(TEXTURE_WRAP_T); //10243
|
||
_INSTALL_CONSTANT(TRIANGLES); //4
|
||
_INSTALL_CONSTANT(TRIANGLE_FAN); //6
|
||
_INSTALL_CONSTANT(TRIANGLE_STRIP); //5
|
||
// _INSTALL_CONSTANT(TRUE); //1
|
||
_INSTALL_CONSTANT(UNPACK_ALIGNMENT); //3317
|
||
_INSTALL_CONSTANT(UNPACK_COLORSPACE_CONVERSION_WEBGL); //37443
|
||
_INSTALL_CONSTANT(UNPACK_FLIP_Y_WEBGL); //37440
|
||
_INSTALL_CONSTANT(UNPACK_PREMULTIPLY_ALPHA_WEBGL); //37441
|
||
_INSTALL_CONSTANT(UNSIGNED_BYTE); //5121
|
||
_INSTALL_CONSTANT(UNSIGNED_INT); //5125
|
||
_INSTALL_CONSTANT(UNSIGNED_SHORT); //5123
|
||
_INSTALL_CONSTANT(UNSIGNED_SHORT_4_4_4_4); //32819
|
||
_INSTALL_CONSTANT(UNSIGNED_SHORT_5_5_5_1); //32820
|
||
_INSTALL_CONSTANT(UNSIGNED_SHORT_5_6_5); //33635
|
||
_INSTALL_CONSTANT(VALIDATE_STATUS); //35715
|
||
_INSTALL_CONSTANT(VENDOR); //7936
|
||
_INSTALL_CONSTANT(VERSION); //7938
|
||
_INSTALL_CONSTANT(VERTEX_ATTRIB_ARRAY_BUFFER_BINDING); //34975
|
||
_INSTALL_CONSTANT(VERTEX_ATTRIB_ARRAY_ENABLED); //34338
|
||
_INSTALL_CONSTANT(VERTEX_ATTRIB_ARRAY_NORMALIZED); //34922
|
||
_INSTALL_CONSTANT(VERTEX_ATTRIB_ARRAY_POINTER); //34373
|
||
_INSTALL_CONSTANT(VERTEX_ATTRIB_ARRAY_SIZE); //34339
|
||
_INSTALL_CONSTANT(VERTEX_ATTRIB_ARRAY_STRIDE); //34340
|
||
_INSTALL_CONSTANT(VERTEX_ATTRIB_ARRAY_TYPE); //34341
|
||
_INSTALL_CONSTANT(VERTEX_SHADER); //35633
|
||
_INSTALL_CONSTANT(VIEWPORT); //2978
|
||
_INSTALL_CONSTANT(ZERO); //0
|
||
|
||
#undef _INSTALL_CONSTANT
|
||
}
|
||
};
|
||
|
||
|
||
// --- C interface -------------------------------------------------------------
|
||
|
||
static std::unordered_map<EXGLContextId, EXGLContext *> EXGLContextMap;
|
||
static std::mutex EXGLContextMapMutex;
|
||
static EXGLContextId EXGLContextNextId = 1;
|
||
|
||
static EXGLContext *EXGLContextGet(EXGLContextId exglCtxId) {
|
||
std::lock_guard<decltype(EXGLContextMapMutex)> lock(EXGLContextMapMutex);
|
||
auto iter = EXGLContextMap.find(exglCtxId);
|
||
if (iter != EXGLContextMap.end()) {
|
||
return iter->second;
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
EXGLContextId EXGLContextCreate(JSGlobalContextRef jsCtx) {
|
||
// Out of ids?
|
||
if (EXGLContextNextId >= std::numeric_limits<EXGLContextId>::max()) {
|
||
EXGLSysLog("Ran out of EXGLContext ids!");
|
||
return 0;
|
||
}
|
||
|
||
// Create C++ object
|
||
EXGLContext *exglCtx;
|
||
EXGLContextId exglCtxId;
|
||
{
|
||
std::lock_guard<decltype(EXGLContextMapMutex)> lock(EXGLContextMapMutex);
|
||
exglCtxId = EXGLContextNextId++;
|
||
if (EXGLContextMap.find(exglCtxId) != EXGLContextMap.end()) {
|
||
EXGLSysLog("Tried to reuse an EXGLContext id. This shouldn't really happen...");
|
||
return 0;
|
||
}
|
||
exglCtx = new EXGLContext(jsCtx, exglCtxId);
|
||
EXGLContextMap[exglCtxId] = exglCtx;
|
||
}
|
||
|
||
// Save JavaScript object
|
||
auto jsGlobal = JSContextGetGlobalObject(jsCtx);
|
||
auto jsEXGLContextMap = (JSObjectRef) EXJSObjectGetPropertyNamed(jsCtx, jsGlobal, "__EXGLContexts");
|
||
if (!JSValueToBoolean(jsCtx, jsEXGLContextMap)) {
|
||
jsEXGLContextMap = JSObjectMake(jsCtx, nullptr, nullptr);
|
||
EXJSObjectSetValueWithUTF8CStringName(jsCtx, jsGlobal, "__EXGLContexts", jsEXGLContextMap);
|
||
}
|
||
std::stringstream ss;
|
||
ss << exglCtxId;
|
||
auto exglCtxIdStr = ss.str();
|
||
EXJSObjectSetValueWithUTF8CStringName(jsCtx, jsEXGLContextMap,
|
||
exglCtxIdStr.c_str(), exglCtx->getJSObject());
|
||
|
||
return exglCtxId;
|
||
}
|
||
|
||
void EXGLContextDestroy(EXGLContextId exglCtxId) {
|
||
std::lock_guard<decltype(EXGLContextMapMutex)> lock(EXGLContextMapMutex);
|
||
|
||
// Destroy C++ object, JavaScript side should just know...
|
||
auto iter = EXGLContextMap.find(exglCtxId);
|
||
if (iter != EXGLContextMap.end()) {
|
||
delete iter->second;
|
||
EXGLContextMap.erase(iter);
|
||
}
|
||
}
|
||
|
||
void EXGLContextFlush(EXGLContextId exglCtxId) {
|
||
EXGLContext *exglCtx = EXGLContextGet(exglCtxId);
|
||
if (exglCtx) {
|
||
exglCtx->flush();
|
||
}
|
||
}
|
||
|
||
void EXGLContextSetDefaultFramebuffer(EXGLContextId exglCtxId, GLint framebuffer) {
|
||
EXGLContext *exglCtx = EXGLContextGet(exglCtxId);
|
||
if (exglCtx) {
|
||
exglCtx->setDefaultFramebuffer(framebuffer);
|
||
}
|
||
}
|