|
do -> # cheap setup |
|
MojoError = cheap.struct [ |
|
cheap.ptr 'char', 'error' |
|
cheap.ptr 'char', 'filename' |
|
cheap.int 'error_position' |
|
] |
|
cheap.typedef 'MojoError', MojoError |
|
|
|
MojoUniform = cheap.struct [ |
|
cheap.int 'type' |
|
cheap.int 'index' |
|
cheap.int 'array_count' |
|
cheap.int 'constant' |
|
cheap.ptr 'char', 'Name' |
|
] |
|
cheap.typedef 'MojoUniform', MojoUniform |
|
|
|
MojoConstant = cheap.struct |
|
type: cheap.int 0 |
|
index: cheap.int 4 |
|
f: cheap.float 8, 4 |
|
i: cheap.int 8, 4 |
|
b: cheap.int 8 |
|
cheap.typedef 'MojoConstant', MojoConstant |
|
|
|
MojoSampler = cheap.struct [ |
|
cheap.int 'type' |
|
cheap.int 'index' |
|
cheap.ptr 'char', 'Name' |
|
cheap.int 'texbem' |
|
] |
|
cheap.typedef 'MojoSampler', MojoSampler |
|
|
|
MojoAttribute = cheap.struct [ |
|
cheap.int 'usage' |
|
cheap.int 'index' |
|
cheap.ptr 'char', 'Name' |
|
] |
|
cheap.typedef 'MojoAttribute', MojoAttribute |
|
|
|
MojoSwizzle = cheap.struct [ |
|
cheap.int 'usage' |
|
cheap.int 'index' |
|
cheap.uchar 'swizzles', 4 |
|
] |
|
cheap.typedef 'MojoSwizzle', MojoSwizzle |
|
|
|
MojoParseData = cheap.struct [ |
|
cheap.int 'error_count' |
|
cheap.ptr 'MojoError', 'errors' |
|
cheap.ptr 'char', 'profile' |
|
cheap.ptr 'char', 'output' |
|
cheap.int 'output_len' |
|
cheap.int 'instruction_count' |
|
cheap.int 'shader_type' |
|
cheap.int 'major_ver' |
|
cheap.int 'minor_ver' |
|
cheap.int 'uniform_count' |
|
cheap.ptr 'MojoUniform', 'uniforms' |
|
cheap.int 'constant_count' |
|
cheap.ptr 'MojoConstant', 'constants' |
|
cheap.int 'sampler_count' |
|
cheap.ptr 'MojoSampler', 'samplers' |
|
cheap.int 'attribute_count' |
|
cheap.ptr 'MojoAttribute', 'attributes' |
|
cheap.int 'output_count' |
|
cheap.ptr 'MojoAttribute', 'outputs' |
|
cheap.int 'swizzle_count' |
|
cheap.ptr 'MojoSwizzle', 'swizzles' |
|
cheap.int 'symbol_count' |
|
cheap.ptr 'void', 'symbols' |
|
cheap.ptr 'void', 'preshader' |
|
cheap.ptr 'void', 'malloc' |
|
cheap.ptr 'void', 'free' |
|
cheap.ptr 'void', 'malloc_data' |
|
] |
|
cheap.typedef 'MojoParseData', MojoParseData |
|
|
|
# make emscripten's heap visible to cheap: |
|
buf = Module.HEAP8.buffer |
|
cheap._heapLast = |
|
a: 0 |
|
l: buf.byteLength |
|
e: buf.byteLength |
|
prev: null |
|
next: null |
|
buf: buf |
|
ui32: Module.HEAPU32 |
|
i32: Module.HEAP32 |
|
ui16: Module.HEAPU16 |
|
i16: Module.HEAP16 |
|
ui8: Module.HEAPU8 |
|
i8: Module.HEAP8 |
|
f32: Module.HEAPF32 |
|
f64: Module.HEAPF64 |
|
null |
|
|
|
emblock = cheap._heapLast |
|
emptr = (t, n) -> |
|
p = cheap.ref emblock |
|
p = p.add n |
|
p.cast t + '*' |
|
|
|
mojoshader = |
|
# enum usageType |
|
usage: ['position', 'blendweight', 'blendindices', 'normal', |
|
'pointsize', 'texcoord', 'tangent', 'binormal', |
|
'tessfactor', 'positiont', 'color', 'fog', 'depth', 'sample'] |
|
|
|
# given a string of hlsl assembly, will output an object with glsl shader |
|
# source and metadata or parse errors if an error occurred. |
|
hlslAsmToGlslRaw: (hlsl) -> |
|
res = {} |
|
bytecode = @assemble hlsl |
|
if bytecode.error_count > 0 |
|
res.errors = @listErrors bytecode |
|
@free bytecode |
|
return res |
|
parsed = @parseGlsl bytecode |
|
@free bytecode |
|
if parsed.error_count > 0 |
|
res.errors = @listErrors parsed |
|
else |
|
res.output = Module.UTF8ToString parsed.output.a |
|
res.slots = parsed.instruction_count |
|
res.type = if parsed.shader_type == 2 then 'vert' else 'frag' |
|
res.version = [parsed.major_ver, parsed.minor_ver] |
|
res.uniforms = for i in [0..parsed.uniform_count-1] by 1 |
|
u = parsed.uniforms.deref i |
|
type: ['float', 'int', 'bool'][u.type] |
|
index: u.index |
|
size: u.array_count |
|
constant: u.constant != 0 |
|
name: Module.UTF8ToString u.Name.a |
|
res.samplers = for i in [0..parsed.sampler_count-1] by 1 |
|
s = parsed.samplers.deref i |
|
type: ['2d', 'cube', 'volume'][s.type] |
|
index: s.index |
|
name: Module.UTF8ToString s.Name.a |
|
res.attributes = for i in [0..parsed.attribute_count-1] by 1 |
|
a = parsed.attributes.deref i |
|
usage: @usage[a.usage] |
|
index: a.index |
|
name: Module.UTF8ToString a.Name.a |
|
res.outputs = for i in [0..parsed.output_count-1] by 1 |
|
a = parsed.outputs.deref i |
|
usage: @usage[a.usage] |
|
index: a.index |
|
name: Module.UTF8ToString a.Name.a |
|
@free parsed |
|
return res |
|
|
|
listErrors: (data) -> |
|
for i in [0..data.error_count-1] by 1 |
|
err = data.errors.deref i |
|
error: Module.UTF8ToString err.error.a |
|
pos: err.error_position |
|
|
|
# see mojoshader.h for the function signatures |
|
assemble: (asm) -> |
|
ptr = Module.ccall('MOJOSHADER_assemble', 'number', |
|
['string', |
|
'string', 'number', |
|
'number', 'number', |
|
'number', 'number', |
|
'number', 'number', |
|
'number', 'number', |
|
'number', 'number', 'number'], |
|
['input', asm, asm.length, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) |
|
emptr('MojoParseData', ptr).deref() |
|
|
|
parseGlsl: (data) -> |
|
ptr = Module.ccall('MOJOSHADER_parse', 'number', [ |
|
'string', |
|
'number', 'number', |
|
'number', 'number', |
|
'number', 'number', |
|
'number', 'number', 'number'], |
|
['glsl120', data.output.a, data.output_len, 0, 0, 0, 0, 0, 0, 0]) |
|
emptr('MojoParseData', ptr).deref() |
|
|
|
free: (data) -> |
|
Module.ccall('MOJOSHADER_freeParseData', null, ['number'], [data.a]) |