mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2025-10-09 22:35:23 +00:00
初始化
This commit is contained in:
415
engine/cocos2d/renderer/core/base-renderer.js
Normal file
415
engine/cocos2d/renderer/core/base-renderer.js
Normal file
@@ -0,0 +1,415 @@
|
||||
// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
import { RecyclePool } from '../memop';
|
||||
import enums from '../enums';
|
||||
import { Vec2, Vec4, Mat3, Mat4, Color, Vec3 } from '../../core/value-types';
|
||||
import ProgramLib from './program-lib';
|
||||
import View from './view';
|
||||
import gfx from '../gfx';
|
||||
|
||||
let _m4_tmp = new Mat4();
|
||||
|
||||
let _stageInfos = new RecyclePool(() => {
|
||||
return {
|
||||
stage: null,
|
||||
items: null,
|
||||
};
|
||||
}, 8);
|
||||
|
||||
let _float2_pool = new RecyclePool(() => {
|
||||
return new Float32Array(2);
|
||||
}, 8);
|
||||
|
||||
let _float3_pool = new RecyclePool(() => {
|
||||
return new Float32Array(3);
|
||||
}, 8);
|
||||
|
||||
let _float4_pool = new RecyclePool(() => {
|
||||
return new Float32Array(4);
|
||||
}, 8);
|
||||
|
||||
let _float9_pool = new RecyclePool(() => {
|
||||
return new Float32Array(9);
|
||||
}, 8);
|
||||
|
||||
let _float16_pool = new RecyclePool(() => {
|
||||
return new Float32Array(16);
|
||||
}, 8);
|
||||
|
||||
let _float64_pool = new RecyclePool(() => {
|
||||
return new Float32Array(64);
|
||||
}, 8);
|
||||
|
||||
let _int2_pool = new RecyclePool(() => {
|
||||
return new Int32Array(2);
|
||||
}, 8);
|
||||
|
||||
let _int3_pool = new RecyclePool(() => {
|
||||
return new Int32Array(3);
|
||||
}, 8);
|
||||
|
||||
let _int4_pool = new RecyclePool(() => {
|
||||
return new Int32Array(4);
|
||||
}, 8);
|
||||
|
||||
let _int64_pool = new RecyclePool(() => {
|
||||
return new Int32Array(64);
|
||||
}, 8);
|
||||
|
||||
export default class Base {
|
||||
/**
|
||||
* @param {gfx.Device} device
|
||||
* @param {Object} opts
|
||||
* @param {gfx.Texture2D} opts.defaultTexture
|
||||
* @param {gfx.TextureCube} opts.defaultTextureCube
|
||||
*/
|
||||
constructor (device, opts) {
|
||||
this._device = device;
|
||||
this._programLib = new ProgramLib(device);
|
||||
this._opts = opts;
|
||||
this._type2defaultValue = {
|
||||
[enums.PARAM_INT]: 0,
|
||||
[enums.PARAM_INT2]: new Vec2(0, 0),
|
||||
[enums.PARAM_INT3]: new Vec3(0, 0, 0),
|
||||
[enums.PARAM_INT4]: new Vec4(0, 0, 0, 0),
|
||||
[enums.PARAM_FLOAT]: 0.0,
|
||||
[enums.PARAM_FLOAT2]: new Vec2(0, 0),
|
||||
[enums.PARAM_FLOAT3]: new Vec3(0, 0, 0),
|
||||
[enums.PARAM_FLOAT4]: new Vec4(0, 0, 0, 0),
|
||||
[enums.PARAM_COLOR4]: new Color(0, 0, 0, 1),
|
||||
[enums.PARAM_MAT3]: new Mat3(),
|
||||
[enums.PARAM_MAT4]: new Mat4(),
|
||||
[enums.PARAM_TEXTURE_2D]: opts.defaultTexture,
|
||||
[enums.PARAM_TEXTURE_CUBE]: opts.defaultTextureCube,
|
||||
};
|
||||
this._stage2fn = {};
|
||||
this._usedTextureUnits = 0;
|
||||
|
||||
this._viewPools = new RecyclePool(() => {
|
||||
return new View();
|
||||
}, 8);
|
||||
|
||||
this._drawItemsPools = new RecyclePool(() => {
|
||||
return {
|
||||
model: null,
|
||||
node: null,
|
||||
ia: null,
|
||||
effect: null,
|
||||
defines: null,
|
||||
uniforms: null
|
||||
};
|
||||
}, 100);
|
||||
|
||||
this._stageItemsPools = new RecyclePool(() => {
|
||||
return new RecyclePool(() => {
|
||||
return {
|
||||
model: null,
|
||||
node: null,
|
||||
ia: null,
|
||||
effect: null,
|
||||
defines: null,
|
||||
passes: [],
|
||||
sortKey: -1,
|
||||
uniforms: null
|
||||
};
|
||||
}, 100);
|
||||
}, 16);
|
||||
|
||||
this._definesChanged = false;
|
||||
}
|
||||
|
||||
_resetTextuerUnit () {
|
||||
this._usedTextureUnits = 0;
|
||||
}
|
||||
|
||||
_allocTextureUnit () {
|
||||
const device = this._device;
|
||||
|
||||
let unit = this._usedTextureUnits;
|
||||
if (unit >= device._caps.maxTextureUnits) {
|
||||
console.warn(`Trying to use ${unit} texture units while this GPU supports only ${device._caps.maxTextureUnits}`);
|
||||
}
|
||||
|
||||
this._usedTextureUnits += 1;
|
||||
return unit;
|
||||
}
|
||||
|
||||
_registerStage (name, fn) {
|
||||
this._stage2fn[name] = fn;
|
||||
}
|
||||
|
||||
clear () {
|
||||
this._programLib.clear();
|
||||
this.reset();
|
||||
}
|
||||
|
||||
reset () {
|
||||
this._viewPools.reset();
|
||||
this._stageItemsPools.reset();
|
||||
|
||||
this._definesChanged = false;
|
||||
}
|
||||
|
||||
_requestView () {
|
||||
return this._viewPools.add();
|
||||
}
|
||||
|
||||
_render (view, scene) {
|
||||
const device = this._device;
|
||||
|
||||
// setup framebuffer
|
||||
device.setFrameBuffer(view._framebuffer);
|
||||
|
||||
// setup viewport
|
||||
device.setViewport(
|
||||
view._rect.x,
|
||||
view._rect.y,
|
||||
view._rect.w,
|
||||
view._rect.h
|
||||
);
|
||||
|
||||
// setup clear
|
||||
let clearOpts = {};
|
||||
if (view._clearFlags & enums.CLEAR_COLOR) {
|
||||
clearOpts.color = Vec4.toArray([], view._color);
|
||||
}
|
||||
if (view._clearFlags & enums.CLEAR_DEPTH) {
|
||||
clearOpts.depth = view._depth;
|
||||
}
|
||||
if (view._clearFlags & enums.CLEAR_STENCIL) {
|
||||
clearOpts.stencil = view._stencil;
|
||||
}
|
||||
device.clear(clearOpts);
|
||||
|
||||
// get all draw items
|
||||
this._drawItemsPools.reset();
|
||||
|
||||
for (let i = 0; i < scene._models.length; ++i) {
|
||||
let model = scene._models.data[i];
|
||||
|
||||
// filter model by view
|
||||
if ((model._cullingMask & view._cullingMask) === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let drawItem = this._drawItemsPools.add();
|
||||
model.extractDrawItem(drawItem);
|
||||
}
|
||||
|
||||
// dispatch draw items to different stage
|
||||
_stageInfos.reset();
|
||||
|
||||
for (let i = 0; i < view._stages.length; ++i) {
|
||||
let stage = view._stages[i];
|
||||
let stageItems = this._stageItemsPools.add();
|
||||
stageItems.reset();
|
||||
|
||||
for (let j = 0; j < this._drawItemsPools.length; ++j) {
|
||||
let drawItem = this._drawItemsPools.data[j];
|
||||
let passes = drawItem.effect.stagePasses[stage];
|
||||
if (!passes || passes.length === 0) continue;
|
||||
|
||||
let stageItem = stageItems.add();
|
||||
stageItem.passes = passes;
|
||||
stageItem.model = drawItem.model;
|
||||
stageItem.node = drawItem.node;
|
||||
stageItem.ia = drawItem.ia;
|
||||
stageItem.effect = drawItem.effect;
|
||||
stageItem.defines = drawItem.defines;
|
||||
stageItem.sortKey = -1;
|
||||
stageItem.uniforms = drawItem.uniforms;
|
||||
}
|
||||
|
||||
let stageInfo = _stageInfos.add();
|
||||
stageInfo.stage = stage;
|
||||
stageInfo.items = stageItems;
|
||||
}
|
||||
|
||||
// render stages
|
||||
for (let i = 0; i < _stageInfos.length; ++i) {
|
||||
let info = _stageInfos.data[i];
|
||||
let fn = this._stage2fn[info.stage];
|
||||
fn(view, info.items);
|
||||
}
|
||||
}
|
||||
|
||||
_setProperty (prop) {
|
||||
const device = this._device;
|
||||
let param = prop.value;
|
||||
|
||||
if (param === undefined) {
|
||||
param = prop.val;
|
||||
}
|
||||
|
||||
if (param === undefined) {
|
||||
param = this._type2defaultValue[prop.type];
|
||||
}
|
||||
|
||||
if (param === undefined) {
|
||||
console.warn(`Failed to set technique property ${prop.name}, value not found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
prop.type === enums.PARAM_TEXTURE_2D ||
|
||||
prop.type === enums.PARAM_TEXTURE_CUBE
|
||||
) {
|
||||
if (Array.isArray(param)) {
|
||||
if (param.length > prop.count) {
|
||||
console.error(`Failed to set property [${prop.name}] : The length of texture array [${param.length}] is bigger than [${prop.count}].`);
|
||||
return;
|
||||
}
|
||||
let slots = _int64_pool.add();
|
||||
for (let index = 0; index < param.length; ++index) {
|
||||
slots[index] = this._allocTextureUnit();
|
||||
}
|
||||
device.setTextureArray(prop.name, param, slots);
|
||||
} else {
|
||||
device.setTexture(prop.name, param, this._allocTextureUnit());
|
||||
}
|
||||
} else {
|
||||
if (prop.directly) {
|
||||
device.setUniformDirectly(prop.name, param);
|
||||
}
|
||||
else {
|
||||
device.setUniform(prop.name, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_draw (item) {
|
||||
const device = this._device;
|
||||
const programLib = this._programLib;
|
||||
const { node, ia, passes, effect } = item;
|
||||
|
||||
// reset the pool
|
||||
// NOTE: we can use drawCounter optimize this
|
||||
// TODO: should be configurable
|
||||
_float2_pool.reset();
|
||||
_float3_pool.reset();
|
||||
_float4_pool.reset();
|
||||
_float9_pool.reset();
|
||||
_float16_pool.reset();
|
||||
_float64_pool.reset();
|
||||
_int2_pool.reset();
|
||||
_int3_pool.reset();
|
||||
_int4_pool.reset();
|
||||
_int64_pool.reset();
|
||||
|
||||
// set common uniforms
|
||||
// TODO: try commit this depends on effect
|
||||
// {
|
||||
node.getWorldMatrix(_m4_tmp);
|
||||
device.setUniform('cc_matWorld', Mat4.toArray(_float16_pool.add(), _m4_tmp));
|
||||
|
||||
// let wq = node.getWorldRotation(cc.quat());
|
||||
Mat4.invert(_m4_tmp, _m4_tmp);
|
||||
Mat4.transpose(_m4_tmp, _m4_tmp);
|
||||
device.setUniform('cc_matWorldIT', Mat4.toArray(_float16_pool.add(), _m4_tmp));
|
||||
// }
|
||||
|
||||
let defines = this._defines;
|
||||
|
||||
// for each pass
|
||||
for (let i = 0; i < passes.length; ++i) {
|
||||
let pass = passes[i];
|
||||
|
||||
if (this._definesChanged) {
|
||||
pass._programKey = null;
|
||||
}
|
||||
|
||||
let count = ia.count;
|
||||
|
||||
// set vertex buffer
|
||||
if (ia._vertexBuffer) {
|
||||
device.setVertexBuffer(0, ia._vertexBuffer);
|
||||
}
|
||||
|
||||
// set index buffer
|
||||
if (ia._indexBuffer) {
|
||||
device.setIndexBuffer(ia._indexBuffer);
|
||||
}
|
||||
|
||||
// set primitive type
|
||||
device.setPrimitiveType(ia._primitiveType);
|
||||
|
||||
// set program
|
||||
Object.setPrototypeOf(defines, pass._defines);
|
||||
|
||||
let program = programLib.getProgram(pass, defines, effect.name);
|
||||
device.setProgram(program);
|
||||
|
||||
let uniforms = program._uniforms;
|
||||
let variants = pass._properties;
|
||||
for (let j = 0; j < uniforms.length; j++) {
|
||||
let prop = variants[uniforms[j].name];
|
||||
if (prop !== undefined)
|
||||
this._setProperty(prop);
|
||||
}
|
||||
|
||||
|
||||
// cull mode
|
||||
device.setCullMode(pass._cullMode);
|
||||
|
||||
// blend
|
||||
if (pass._blend) {
|
||||
device.enableBlend();
|
||||
device.setBlendFuncSep(
|
||||
pass._blendSrc,
|
||||
pass._blendDst,
|
||||
pass._blendSrcAlpha,
|
||||
pass._blendDstAlpha
|
||||
);
|
||||
device.setBlendEqSep(
|
||||
pass._blendEq,
|
||||
pass._blendAlphaEq
|
||||
);
|
||||
device.setBlendColor32(pass._blendColor);
|
||||
}
|
||||
|
||||
// depth test & write
|
||||
if (pass._depthTest) {
|
||||
device.enableDepthTest();
|
||||
device.setDepthFunc(pass._depthFunc);
|
||||
}
|
||||
if (pass._depthWrite) {
|
||||
device.enableDepthWrite();
|
||||
}
|
||||
|
||||
// stencil
|
||||
device.setStencilTest(pass._stencilTest);
|
||||
if (pass._stencilTest === gfx.STENCIL_ENABLE) {
|
||||
// front
|
||||
device.setStencilFuncFront(
|
||||
pass._stencilFuncFront,
|
||||
pass._stencilRefFront,
|
||||
pass._stencilMaskFront
|
||||
);
|
||||
device.setStencilOpFront(
|
||||
pass._stencilFailOpFront,
|
||||
pass._stencilZFailOpFront,
|
||||
pass._stencilZPassOpFront,
|
||||
pass._stencilWriteMaskFront
|
||||
);
|
||||
|
||||
// back
|
||||
device.setStencilFuncBack(
|
||||
pass._stencilFuncBack,
|
||||
pass._stencilRefBack,
|
||||
pass._stencilMaskBack
|
||||
);
|
||||
device.setStencilOpBack(
|
||||
pass._stencilFailOpBack,
|
||||
pass._stencilZFailOpBack,
|
||||
pass._stencilZPassOpBack,
|
||||
pass._stencilWriteMaskBack
|
||||
);
|
||||
}
|
||||
|
||||
// draw pass
|
||||
device.draw(ia._start, count);
|
||||
|
||||
this._resetTextuerUnit();
|
||||
}
|
||||
}
|
||||
}
|
13
engine/cocos2d/renderer/core/constants.js
Normal file
13
engine/cocos2d/renderer/core/constants.js
Normal file
@@ -0,0 +1,13 @@
|
||||
let RenderQueue = {
|
||||
OPAQUE: 0,
|
||||
TRANSPARENT: 1,
|
||||
OVERLAY: 2
|
||||
};
|
||||
|
||||
let PassStage = {
|
||||
DEFAULT: 1,
|
||||
FORWARD: 2,
|
||||
SHADOWCAST: 4
|
||||
};
|
||||
|
||||
export { RenderQueue, PassStage };
|
35
engine/cocos2d/renderer/core/input-assembler.js
Normal file
35
engine/cocos2d/renderer/core/input-assembler.js
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
import gfx from '../gfx';
|
||||
|
||||
export default class InputAssembler {
|
||||
constructor(vb, ib, pt = gfx.PT_TRIANGLES) {
|
||||
this._vertexBuffer = vb;
|
||||
this._indexBuffer = ib;
|
||||
this._primitiveType = pt;
|
||||
this._start = 0;
|
||||
this._count = -1;
|
||||
|
||||
// TODO: instancing data
|
||||
// this._stream = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @property {Number} count The number of indices or vertices to dispatch in the draw call.
|
||||
*/
|
||||
get count() {
|
||||
if (this._count !== -1) {
|
||||
return this._count;
|
||||
}
|
||||
|
||||
if (this._indexBuffer) {
|
||||
return this._indexBuffer.count;
|
||||
}
|
||||
|
||||
if (this._vertexBuffer) {
|
||||
return this._vertexBuffer.count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
246
engine/cocos2d/renderer/core/pass.js
Normal file
246
engine/cocos2d/renderer/core/pass.js
Normal file
@@ -0,0 +1,246 @@
|
||||
// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
import gfx from '../gfx';
|
||||
import enums from '../enums';
|
||||
import ValueType from '../../core/value-types/value-type';
|
||||
|
||||
export default class Pass {
|
||||
constructor (name, detailName, programName, stage, properties = {}, defines = {}) {
|
||||
this._name = name;
|
||||
this._detailName = detailName;
|
||||
this._programName = programName;
|
||||
this._programKey = null;
|
||||
this._stage = stage;
|
||||
this._properties = properties;
|
||||
this._defines = defines;
|
||||
|
||||
this._propertyNames = Object.keys(properties)
|
||||
this._defineNames = Object.keys(defines)
|
||||
|
||||
// cullmode
|
||||
this._cullMode = gfx.CULL_BACK;
|
||||
|
||||
// blending
|
||||
this._blend = false;
|
||||
this._blendEq = gfx.BLEND_FUNC_ADD;
|
||||
this._blendAlphaEq = gfx.BLEND_FUNC_ADD;
|
||||
this._blendSrc = gfx.BLEND_SRC_ALPHA;
|
||||
this._blendDst = gfx.BLEND_ONE_MINUS_SRC_ALPHA;
|
||||
this._blendSrcAlpha = gfx.BLEND_SRC_ALPHA;
|
||||
this._blendDstAlpha = gfx.BLEND_ONE_MINUS_SRC_ALPHA;
|
||||
this._blendColor = 0xffffffff;
|
||||
|
||||
// depth
|
||||
this._depthTest = false;
|
||||
this._depthWrite = false;
|
||||
this._depthFunc = gfx.DS_FUNC_LESS,
|
||||
|
||||
// stencil
|
||||
this._stencilTest = gfx.STENCIL_INHERIT;
|
||||
|
||||
// front
|
||||
this._stencilFuncFront = gfx.DS_FUNC_ALWAYS;
|
||||
this._stencilRefFront = 0;
|
||||
this._stencilMaskFront = 0xff;
|
||||
this._stencilFailOpFront = gfx.STENCIL_OP_KEEP;
|
||||
this._stencilZFailOpFront = gfx.STENCIL_OP_KEEP;
|
||||
this._stencilZPassOpFront = gfx.STENCIL_OP_KEEP;
|
||||
this._stencilWriteMaskFront = 0xff;
|
||||
// back
|
||||
this._stencilFuncBack = gfx.DS_FUNC_ALWAYS;
|
||||
this._stencilRefBack = 0;
|
||||
this._stencilMaskBack = 0xff;
|
||||
this._stencilFailOpBack = gfx.STENCIL_OP_KEEP;
|
||||
this._stencilZFailOpBack = gfx.STENCIL_OP_KEEP;
|
||||
this._stencilZPassOpBack = gfx.STENCIL_OP_KEEP;
|
||||
this._stencilWriteMaskBack = 0xff;
|
||||
}
|
||||
|
||||
setCullMode (cullMode = gfx.CULL_BACK) {
|
||||
this._cullMode = cullMode;
|
||||
}
|
||||
|
||||
setBlend (
|
||||
enabled = false,
|
||||
blendEq = gfx.BLEND_FUNC_ADD,
|
||||
blendSrc = gfx.BLEND_SRC_ALPHA,
|
||||
blendDst = gfx.BLEND_ONE_MINUS_SRC_ALPHA,
|
||||
blendAlphaEq = gfx.BLEND_FUNC_ADD,
|
||||
blendSrcAlpha = gfx.BLEND_SRC_ALPHA,
|
||||
blendDstAlpha = gfx.BLEND_ONE_MINUS_SRC_ALPHA,
|
||||
blendColor = 0xffffffff
|
||||
) {
|
||||
this._blend = enabled;
|
||||
this._blendEq = blendEq;
|
||||
this._blendSrc = blendSrc;
|
||||
this._blendDst = blendDst;
|
||||
this._blendAlphaEq = blendAlphaEq;
|
||||
this._blendSrcAlpha = blendSrcAlpha;
|
||||
this._blendDstAlpha = blendDstAlpha;
|
||||
this._blendColor = blendColor;
|
||||
}
|
||||
|
||||
setDepth (
|
||||
depthTest = false,
|
||||
depthWrite = false,
|
||||
depthFunc = gfx.DS_FUNC_LESS
|
||||
) {
|
||||
this._depthTest = depthTest;
|
||||
this._depthWrite = depthWrite;
|
||||
this._depthFunc = depthFunc;
|
||||
}
|
||||
|
||||
setStencilFront (
|
||||
enabled = gfx.STENCIL_INHERIT,
|
||||
stencilFunc = gfx.DS_FUNC_ALWAYS,
|
||||
stencilRef = 0,
|
||||
stencilMask = 0xff,
|
||||
stencilFailOp = gfx.STENCIL_OP_KEEP,
|
||||
stencilZFailOp = gfx.STENCIL_OP_KEEP,
|
||||
stencilZPassOp = gfx.STENCIL_OP_KEEP,
|
||||
stencilWriteMask = 0xff
|
||||
) {
|
||||
this._stencilTest = enabled;
|
||||
this._stencilFuncFront = stencilFunc;
|
||||
this._stencilRefFront = stencilRef;
|
||||
this._stencilMaskFront = stencilMask;
|
||||
this._stencilFailOpFront = stencilFailOp;
|
||||
this._stencilZFailOpFront = stencilZFailOp;
|
||||
this._stencilZPassOpFront = stencilZPassOp;
|
||||
this._stencilWriteMaskFront = stencilWriteMask;
|
||||
}
|
||||
|
||||
setStencilEnabled (stencilTest = gfx.STENCIL_INHERIT) {
|
||||
this._stencilTest = stencilTest;
|
||||
}
|
||||
|
||||
setStencilBack (
|
||||
stencilTest = gfx.STENCIL_INHERIT,
|
||||
stencilFunc = gfx.DS_FUNC_ALWAYS,
|
||||
stencilRef = 0,
|
||||
stencilMask = 0xff,
|
||||
stencilFailOp = gfx.STENCIL_OP_KEEP,
|
||||
stencilZFailOp = gfx.STENCIL_OP_KEEP,
|
||||
stencilZPassOp = gfx.STENCIL_OP_KEEP,
|
||||
stencilWriteMask = 0xff
|
||||
) {
|
||||
this._stencilTest = stencilTest;
|
||||
this._stencilFuncBack = stencilFunc;
|
||||
this._stencilRefBack = stencilRef;
|
||||
this._stencilMaskBack = stencilMask;
|
||||
this._stencilFailOpBack = stencilFailOp;
|
||||
this._stencilZFailOpBack = stencilZFailOp;
|
||||
this._stencilZPassOpBack = stencilZPassOp;
|
||||
this._stencilWriteMaskBack = stencilWriteMask;
|
||||
}
|
||||
|
||||
setStage (stage) {
|
||||
this._stage = stage;
|
||||
}
|
||||
|
||||
setProperties (properties) {
|
||||
this._properties = properties;
|
||||
}
|
||||
|
||||
getProperty (name) {
|
||||
if (!this._properties[name]) {
|
||||
return;
|
||||
}
|
||||
return this._properties[name].value;
|
||||
}
|
||||
|
||||
setProperty (name, value, directly) {
|
||||
let prop = this._properties[name];
|
||||
if (!prop) {
|
||||
return false;
|
||||
}
|
||||
|
||||
prop.directly = directly;
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
let array = prop.value;
|
||||
if (array.length !== value.length) {
|
||||
cc.warnID(9105, this._name, name);
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
array[i] = value[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (value && !ArrayBuffer.isView(value)) {
|
||||
if (prop.type === enums.PARAM_TEXTURE_2D) {
|
||||
prop.value = value.getImpl();
|
||||
}
|
||||
else if (value instanceof ValueType) {
|
||||
value.constructor.toArray(prop.value, value);
|
||||
}
|
||||
else {
|
||||
if (typeof value === 'object') {
|
||||
cc.warnID(9106, this._name, name);
|
||||
}
|
||||
prop.value = value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
prop.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
getDefine (name) {
|
||||
return this._defines[name];
|
||||
}
|
||||
|
||||
define (name, value, force) {
|
||||
let oldValue = this._defines[name];
|
||||
|
||||
if (!force && oldValue === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (oldValue !== value) {
|
||||
this._defines[name] = value;
|
||||
this._programKey = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
clone () {
|
||||
let pass = new Pass(this._programName);
|
||||
Object.assign(pass, this);
|
||||
|
||||
let newProperties = {};
|
||||
let properties = this._properties;
|
||||
for (let name in properties) {
|
||||
let prop = properties[name];
|
||||
let newProp = newProperties[name] = {};
|
||||
|
||||
let value = prop.value;
|
||||
if (Array.isArray(value)) {
|
||||
newProp.value = value.concat();
|
||||
}
|
||||
else if (ArrayBuffer.isView(value)) {
|
||||
newProp.value = new value.__proto__.constructor(value);
|
||||
}
|
||||
else {
|
||||
newProp.value = value;
|
||||
}
|
||||
|
||||
for (let name in prop) {
|
||||
if (name === 'value') continue;
|
||||
newProp[name] = prop[name];
|
||||
}
|
||||
}
|
||||
|
||||
pass._properties = newProperties;
|
||||
pass._defines = Object.assign({}, this._defines);
|
||||
pass._propertyNames = this._propertyNames;
|
||||
pass._defineNames = this._defineNames;
|
||||
|
||||
return pass;
|
||||
}
|
||||
}
|
262
engine/cocos2d/renderer/core/program-lib.js
Normal file
262
engine/cocos2d/renderer/core/program-lib.js
Normal file
@@ -0,0 +1,262 @@
|
||||
// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
import gfx from '../gfx';
|
||||
|
||||
let _shdID = 0;
|
||||
|
||||
function _generateDefines(tmpDefines, defines) {
|
||||
let results = [];
|
||||
for (let i = 0; i < tmpDefines.length; i++) {
|
||||
let name = tmpDefines[i].name;
|
||||
let value = defines[name];
|
||||
if (typeof value !== 'number') {
|
||||
value = value ? 1 : 0;
|
||||
}
|
||||
results.push(`#define ${name} ${value}`);
|
||||
}
|
||||
return results.join('\n') + '\n';
|
||||
}
|
||||
|
||||
function _replaceMacroNums(string, tmpDefines, defines) {
|
||||
let tmp = string;
|
||||
|
||||
for (let i = 0; i < tmpDefines.length; i++) {
|
||||
let name = tmpDefines[i].name;
|
||||
let value = defines[name];
|
||||
if (Number.isInteger(value)) {
|
||||
let reg = new RegExp(name, 'g');
|
||||
tmp = tmp.replace(reg, value);
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
function _unrollLoops(string) {
|
||||
let pattern = /#pragma for (\w+) in range\(\s*(\d+)\s*,\s*(\d+)\s*\)([\s\S]+?)#pragma endFor/g;
|
||||
function replace(match, index, begin, end, snippet) {
|
||||
let unroll = '';
|
||||
let parsedBegin = parseInt(begin);
|
||||
let parsedEnd = parseInt(end);
|
||||
if (parsedBegin.isNaN || parsedEnd.isNaN) {
|
||||
console.error('Unroll For Loops Error: begin and end of range must be an int num.');
|
||||
}
|
||||
for (let i = parsedBegin; i < parsedEnd; ++i) {
|
||||
unroll += snippet.replace(new RegExp(`{${index}}`, 'g'), i);
|
||||
}
|
||||
return unroll;
|
||||
}
|
||||
return string.replace(pattern, replace);
|
||||
}
|
||||
|
||||
function _replaceHighp(string) {
|
||||
return string.replace(/\bhighp\b/g, 'mediump');
|
||||
}
|
||||
|
||||
export default class ProgramLib {
|
||||
/**
|
||||
* @param {gfx.Device} device
|
||||
*/
|
||||
constructor(device) {
|
||||
this._device = device;
|
||||
|
||||
// register templates
|
||||
this._templates = {};
|
||||
this._cache = {};
|
||||
|
||||
this._checkPrecision();
|
||||
}
|
||||
|
||||
clear () {
|
||||
this._templates = {};
|
||||
this._cache = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {string} vert
|
||||
* @param {string} frag
|
||||
* @param {Object[]} defines
|
||||
*
|
||||
* @example:
|
||||
* // this object is auto-generated from your actual shaders
|
||||
* let program = {
|
||||
* name: 'foobar',
|
||||
* vert: vertTmpl,
|
||||
* frag: fragTmpl,
|
||||
* defines: [
|
||||
* { name: 'shadow', type: 'boolean' },
|
||||
* { name: 'lightCount', type: 'number', min: 1, max: 4 }
|
||||
* ],
|
||||
* attributes: [{ name: 'a_position', type: 'vec3' }],
|
||||
* uniforms: [{ name: 'color', type: 'vec4' }],
|
||||
* extensions: ['GL_OES_standard_derivatives'],
|
||||
* };
|
||||
* programLib.define(program);
|
||||
*/
|
||||
define(prog) {
|
||||
let { name, defines, glsl1 } = prog;
|
||||
let { vert, frag } = glsl1 || prog;
|
||||
if (this._templates[name]) {
|
||||
// console.warn(`Failed to define shader ${name}: already exists.`);
|
||||
return;
|
||||
}
|
||||
|
||||
let id = ++_shdID;
|
||||
|
||||
// calculate option mask offset
|
||||
let offset = 0;
|
||||
for (let i = 0; i < defines.length; ++i) {
|
||||
let def = defines[i];
|
||||
let cnt = 1;
|
||||
|
||||
if (def.type === 'number') {
|
||||
let range = def.range || [];
|
||||
def.min = range[0] || 0;
|
||||
def.max = range[1] || 4;
|
||||
cnt = Math.ceil(Math.log2(def.max - def.min));
|
||||
|
||||
def._map = function (value) {
|
||||
return (value - this.min) << this._offset;
|
||||
}.bind(def);
|
||||
} else { // boolean
|
||||
def._map = function (value) {
|
||||
if (value) {
|
||||
return 1 << this._offset;
|
||||
}
|
||||
return 0;
|
||||
}.bind(def);
|
||||
}
|
||||
|
||||
def._offset = offset;
|
||||
offset += cnt;
|
||||
}
|
||||
|
||||
let uniforms = prog.uniforms || [];
|
||||
|
||||
if (prog.samplers) {
|
||||
for (let i = 0; i < prog.samplers.length; i++) {
|
||||
uniforms.push(prog.samplers[i])
|
||||
}
|
||||
}
|
||||
if (prog.blocks) {
|
||||
for (let i = 0; i < prog.blocks.length; i++) {
|
||||
let defines = prog.blocks[i].defines;
|
||||
let members = prog.blocks[i].members;
|
||||
for (let j = 0; j < members.length; j++) {
|
||||
uniforms.push({
|
||||
defines,
|
||||
name: members[j].name,
|
||||
type: members[j].type,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// store it
|
||||
this._templates[name] = {
|
||||
id,
|
||||
name,
|
||||
vert,
|
||||
frag,
|
||||
defines,
|
||||
attributes: prog.attributes,
|
||||
uniforms,
|
||||
extensions: prog.extensions
|
||||
};
|
||||
}
|
||||
|
||||
getTemplate(name) {
|
||||
return this._templates[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this library has the specified program?
|
||||
* @param {string} name
|
||||
* @returns {boolean}
|
||||
*/
|
||||
hasProgram(name) {
|
||||
return this._templates[name] !== undefined;
|
||||
}
|
||||
|
||||
getKey(name, defines) {
|
||||
let tmpl = this._templates[name];
|
||||
let key = 0;
|
||||
for (let i = 0; i < tmpl.defines.length; ++i) {
|
||||
let tmplDefs = tmpl.defines[i];
|
||||
|
||||
let value = defines[tmplDefs.name];
|
||||
if (value === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
key |= tmplDefs._map(value);
|
||||
}
|
||||
|
||||
// return key << 8 | tmpl.id;
|
||||
// key number maybe bigger than 32 bit, need use string to store value.
|
||||
return tmpl.id + ':' + key;
|
||||
}
|
||||
|
||||
getProgram(pass, defines, errPrefix) {
|
||||
let key = pass._programKey = pass._programKey || this.getKey(pass._programName, defines);
|
||||
let program = this._cache[key];
|
||||
if (program) {
|
||||
return program;
|
||||
}
|
||||
|
||||
// get template
|
||||
let tmpl = this._templates[pass._programName];
|
||||
let customDef = _generateDefines(tmpl.defines, defines);
|
||||
let vert = _replaceMacroNums(tmpl.vert, tmpl.defines, defines);
|
||||
vert = customDef + _unrollLoops(vert);
|
||||
if (!this._highpSupported) {
|
||||
vert = _replaceHighp(vert);
|
||||
}
|
||||
|
||||
let frag = _replaceMacroNums(tmpl.frag, tmpl.defines, defines);
|
||||
frag = customDef + _unrollLoops(frag);
|
||||
if (!this._highpSupported) {
|
||||
frag = _replaceHighp(frag);
|
||||
}
|
||||
|
||||
program = new gfx.Program(this._device, {
|
||||
vert,
|
||||
frag
|
||||
});
|
||||
let errors = program.link();
|
||||
if (errors) {
|
||||
let vertLines = vert.split('\n');
|
||||
let fragLines = frag.split('\n');
|
||||
let defineLength = tmpl.defines.length;
|
||||
errors.forEach(err => {
|
||||
let line = err.line - 1;
|
||||
let originLine = err.line - defineLength;
|
||||
|
||||
let lines = err.type === 'vs' ? vertLines : fragLines;
|
||||
// let source = ` ${lines[line-1]}\n>${lines[line]}\n ${lines[line+1]}`;
|
||||
let source = lines[line];
|
||||
|
||||
let info = err.info || `Failed to compile ${err.type} ${err.fileID} (ln ${originLine}): \n ${err.message}: \n ${source}`;
|
||||
cc.error(`${errPrefix} : ${info}`);
|
||||
})
|
||||
}
|
||||
this._cache[key] = program;
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
_checkPrecision () {
|
||||
let gl = this._device._gl;
|
||||
let highpSupported = false;
|
||||
if (gl.getShaderPrecisionFormat) {
|
||||
let vertHighp = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT);
|
||||
let fragHighp = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
|
||||
highpSupported = (vertHighp && vertHighp.precision > 0) &&
|
||||
(fragHighp && fragHighp.precision > 0);
|
||||
}
|
||||
if (!highpSupported) {
|
||||
cc.warnID(9102);
|
||||
}
|
||||
this._highpSupported = highpSupported;
|
||||
}
|
||||
}
|
24
engine/cocos2d/renderer/core/technique.js
Normal file
24
engine/cocos2d/renderer/core/technique.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
export default class Technique {
|
||||
constructor(name, passes) {
|
||||
this._name = name;
|
||||
this._passes = passes;
|
||||
}
|
||||
|
||||
get name () {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
get passes() {
|
||||
return this._passes;
|
||||
}
|
||||
|
||||
clone () {
|
||||
let passes = [];
|
||||
for (let i = 0; i < this._passes.length; i++) {
|
||||
passes.push(this._passes[i].clone());
|
||||
}
|
||||
return new Technique(this._name, passes);
|
||||
}
|
||||
}
|
80
engine/cocos2d/renderer/core/view.js
Normal file
80
engine/cocos2d/renderer/core/view.js
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
import { Vec3, Mat4, Vec4 } from '../../core/value-types';
|
||||
import enums from '../enums';
|
||||
|
||||
let _m4_tmp = new Mat4();
|
||||
let _genID = 0;
|
||||
|
||||
/**
|
||||
* A representation of a single camera view
|
||||
*/
|
||||
export default class View {
|
||||
/**
|
||||
* Setup a default view
|
||||
*/
|
||||
constructor() {
|
||||
this._id = _genID++;
|
||||
|
||||
// priority. the smaller one will be rendered first
|
||||
this._priority = 0;
|
||||
|
||||
// viewport
|
||||
this._rect = {
|
||||
x: 0, y: 0, w: 1, h: 1
|
||||
};
|
||||
|
||||
// TODO:
|
||||
// this._scissor = {
|
||||
// x: 0, y: 0, w: 1, h: 1
|
||||
// };
|
||||
|
||||
// clear options
|
||||
this._color = new Vec4(0.3, 0.3, 0.3, 1);
|
||||
this._depth = 1;
|
||||
this._stencil = 0;
|
||||
this._clearFlags = enums.CLEAR_COLOR | enums.CLEAR_DEPTH;
|
||||
this._clearModel = null;
|
||||
|
||||
// matrix
|
||||
this._matView = cc.mat4();
|
||||
this._matViewInv = cc.mat4();
|
||||
this._matProj = cc.mat4();
|
||||
this._matViewProj = cc.mat4();
|
||||
this._matInvViewProj = cc.mat4();
|
||||
|
||||
// stages & framebuffer
|
||||
this._stages = [];
|
||||
this._cullingByID = false;
|
||||
this._framebuffer = null;
|
||||
|
||||
this._shadowLight = null; // TODO: should not refer light in view.
|
||||
|
||||
this._cullingMask = 0xffffffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view's forward direction
|
||||
* @param {Vec3} out the receiving vector
|
||||
* @returns {Vec3} the receiving vector
|
||||
*/
|
||||
getForward(out) {
|
||||
let m = this._matView.m;
|
||||
return Vec3.set(
|
||||
out,
|
||||
-m[2],
|
||||
-m[6],
|
||||
-m[10]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view's observing location
|
||||
* @param {Vec3} out the receiving vector
|
||||
* @returns {Vec3} the receiving vector
|
||||
*/
|
||||
getPosition(out) {
|
||||
Mat4.invert(_m4_tmp, this._matView);
|
||||
return Mat4.getTranslation(out, _m4_tmp);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user