/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include #include "raytracer/raytracer_core.h" #include "core/shader_block.h" #include "core/geometry.h" #include "core/object.h" using namespace GS::Core; using namespace GS::Raytrace; //------------------------------------------------------------------------------ bool Raytracer::EvaluateShaderBlock(const Trace &trace, const ShaderBlock *block, ShaderBlockValue &out) { ShaderBlockValue in[4]; // No more than 4 inputs supported. // Validity check. if (!block) return true; // Evaluate inputs. for (uint n = 0; n < block->GetInputCount(); ++n) if (!EvaluateShaderBlock(trace, block->GetInput(n), in[n])) return false; // Evaluate block. switch (block->type) { case ShaderBlock::TypeGeometryVertex: out.Set(trace.pi * trace.o->GetInverseMatrix()); break; case ShaderBlock::TypeGeometryNormal: if (Vector4 *nrm = trace.g->vtx_normal) { Vector4 &nm0 = nrm[trace.bi], &nm1 = nrm[trace.bi + trace.it + 1], &nm2 = nrm[trace.bi + trace.it + 2]; out.Set(nm0 * trace.w + nm1 * trace.u + nm2 * trace.v); } break; case ShaderBlock::TypeGeometryVertexColor: if (Vector4 *rgb = trace.g->rgb) { Vector4 &cl0 = rgb[trace.bi], &cl1 = rgb[trace.bi + trace.it + 1], &cl2 = rgb[trace.bi + trace.it + 2]; out.Set(cl0 * trace.w + cl1 * trace.u + cl2 * trace.v); } break; case ShaderBlock::TypeGeometryUV: { GeometryUVShaderBlock *b = (GeometryUVShaderBlock *)block; if (Vector2 *uv = trace.g->uv[b->channel]) { Vector2 &uv0 = uv[trace.bi], &uv1 = uv[trace.bi + trace.it + 1], &uv2 = uv[trace.bi + trace.it + 2]; out.Set(Vector4(trace.w * uv0.x + trace.u * uv1.x + trace.v * uv2.x, trace.w * uv0.y + trace.u * uv1.y + trace.v * uv2.y, 0, 0)); } } break; case ShaderBlock::TypeGeometrySkinning: break; case ShaderBlock::TypeGeometryTangentFrame: { Vector4 sample = ( trace.g->vtx_normal[trace.bi] * trace.w + trace.g->vtx_normal[trace.bi + trace.it + 1] * trace.u + trace.g->vtx_normal[trace.bi + trace.it + 2] * trace.v ).Normalized(); Vector4 T, B; if (trace.g->vtx_tangent) { // Interpolated tangent basis. T = (trace.g->vtx_tangent[trace.bi + 0].T * trace.w + trace.g->vtx_tangent[trace.bi + trace.it + 1].T * trace.u + trace.g->vtx_tangent[trace.bi + trace.it + 2].T * trace.v ).Normalized(); B = (trace.g->vtx_tangent[trace.bi + 0].B * trace.w + trace.g->vtx_tangent[trace.bi + trace.it + 1].B * trace.u + trace.g->vtx_tangent[trace.bi + trace.it + 2].B * trace.v ).Normalized(); } else { T.Set(1, 0, 0); B.Set(0, 1, 0); } // Build tangent frame. Matrix3 tangent_matrix(T, B, sample); out.Set(tangent_matrix); } break; case ShaderBlock::TypeTexture: out.Set(((TextureShaderBlock *)block)->texture); break; case ShaderBlock::TypeTextureSampler: { if (in[0].t) { Color sample; if (Picture *p = gf->LoadPicture(in[0].t)) p->SampleRGBA(in[1].v.x < 0 ? 1 + fmodf(in[1].v.x, 1) : fmodf(in[1].v.x, 1), in[1].v.y < 0 ? 1 + fmodf(in[1].v.y, 1) : fmodf(in[1].v.y, 1), sample); out.Set(sample); } else out.Set(Vector4(0, 0, 0)); } break; case ShaderBlock::TypeConstant: { ConstantShaderBlock *b = (ConstantShaderBlock *)block; out.Set(Vector4(b->constant[0], b->constant[1], b->constant[2], b->constant[3])); } break; case ShaderBlock::TypeColor: { ColorShaderBlock *b = (ColorShaderBlock *)block; out.Set(b->color); } break; case ShaderBlock::TypeMaterialParam: { MaterialParamShaderBlock *b = (MaterialParamShaderBlock *)block; switch (b->param) { case MaterialParamShaderBlock::MaterialAmbient: out.Set(trace.m->ambient); break; case MaterialParamShaderBlock::MaterialDiffuse: out.Set(trace.m->diffuse); break; case MaterialParamShaderBlock::MaterialSpecular: out.Set(trace.m->specular); break; case MaterialParamShaderBlock::MaterialSelf: out.Set(trace.m->self); break; case MaterialParamShaderBlock::MaterialGlossiness: out.Set(trace.m->glossiness); break; case MaterialParamShaderBlock::MaterialOpacity: out.Set(trace.m->opacity); break; case MaterialParamShaderBlock::MaterialReflection: out.Set(trace.m->reflection); break; } } break; case ShaderBlock::TypeScreenUV: out.Set(Vector4(0.5f,0.5f,0.5f)); break; case ShaderBlock::TypeViewVector: out.Set(trace.d); break; case ShaderBlock::TypeNormalViewMatrix: out.Set(Matrix3::FromOrthonormalBasis(trace.d).Transposed() * trace.o->GetRotationMatrix()); break; case ShaderBlock::TypeNormalMatrix: out.Set(trace.o->GetRotationMatrix()); break; case ShaderBlock::TypeModelViewMatrix: { Matrix4 view_matrix = Matrix4::FromMatrix3(Matrix3::FromOrthonormalBasis(trace.d).Transposed()); view_matrix.SetRow(3, trace.s.Reversed()); out.Set(view_matrix * trace.o->GetMatrix()); } break; case ShaderBlock::TypeModelMatrix: out.Set(trace.o->GetMatrix()); break; case ShaderBlock::TypeMix: out.Set(in[0].v * in[2].v.x + in[1].v * (1 - in[2].v.x)); break; case ShaderBlock::TypeAdd: out.Set(in[0].v + in[1].v); break; case ShaderBlock::TypeMul: { if (in[0].type == in[1].type) switch (in[0].type) { case ShaderBlockValue::BlockValueVector: out.Set(in[0].v * in[1].v); break; case ShaderBlockValue::BlockValueMatrix3: out.Set(in[0].m3 * in[1].m3); break; case ShaderBlockValue::BlockValueMatrix4: out.Set(in[0].m4 * in[1].m4); break; } else { ShaderBlockValue *_a = &in[0], *_b = &in[1]; if (_b->type < _a->type) { ShaderBlockValue *tmp = _a; _a = _b; _b = tmp; } if (_a->type == ShaderBlockValue::BlockValueVector) { if (_b->type == ShaderBlockValue::BlockValueMatrix3) out.Set(_a->v * _b->m3); else if (_b->type == ShaderBlockValue::BlockValueMatrix4) out.Set(_a->v * _b->m4); } } } break; case ShaderBlock::TypeSub: out.Set(in[0].v - in[1].v); break; case ShaderBlock::TypeDiv: out.Set(in[0].v / in[1].v); break; case ShaderBlock::TypeDot: out.Set(in[0].v.Dot(in[1].v)); break; case ShaderBlock::TypeCross: out.Set(in[0].v.Cross(in[1].v)); break; case ShaderBlock::TypeClamp: out.Set(Vector4( Types::Clamp(in[0].v.x, in[1].v.x, in[2].v.x), Types::Clamp(in[0].v.y, in[1].v.y, in[2].v.y), Types::Clamp(in[0].v.z, in[1].v.z, in[2].v.z), Types::Clamp(in[0].v.w, in[1].v.w, in[2].v.w) ) ); break; case ShaderBlock::TypeNormalize: out.Set(in[0].v.Normalized()); break; case ShaderBlock::TypeSwizzle: { SwizzleShaderBlock *b = (SwizzleShaderBlock *)block; Vector4 v(0, 0, 0); for (int n = 0; n < 4; ++n) if (b->swizzle[n] != SwizzleShaderBlock::SwizzleNone) v[n] = in[0].v[b->swizzle[n] - SwizzleShaderBlock::SwizzleX]; out.Set(v); } break; case ShaderBlock::TypeBuild: { BuildShaderBlock *b = (BuildShaderBlock *)block; Vector4 v(0, 0, 0); for (int n = 0; n < 4; ++n) { if (b->build[n] == BuildShaderBlock::BuildOne) v[n] = 1; else if (b->build[n] == BuildShaderBlock::BuildZero) v[n] = 0; else v[n] = in[n].v[b->build[n] - BuildShaderBlock::BuildX]; } out.Set(v); } break; case ShaderBlock::TypeSin: out.Set(sin(in[0].v.x)); break; case ShaderBlock::TypeCos: out.Set(cos(in[0].v.x)); break; case ShaderBlock::TypeUnpackColorToVector: out.Set((in[0].v - Vector4(0.5, 0.5, 0.0)) * Vector4(2.0, 2.0, 1.0)); break; case ShaderBlock::TypePackVectorToColor: out.Set((in[0].v + Vector4(1.0, 1.0, 0.0)) * Vector4(0.5, 0.5, 1.0)); break; case ShaderBlock::TypeClock: out.Set(render_clock); break; case ShaderBlock::TypePow: out.Set(float(pow(in[0].v.x, in[1].v.x))); break; case ShaderBlock::TypeAbs: if (in[0].type == ShaderBlockValue::BlockValueVector) { Vector4 o = in[0].v.Abs(); out.Set(Vector4(o.x, o.y, o.z)); } break; } return true; } //------------------------------------------------------------------------------