So I've been messing around with this for over a week now it seems.
This is a minimal example that is as close to a straight port of
Fallout's Simple Shadow Shader tutorial as I can get. It makes use of a custom Matrix4 class since the built-in one simply wouldn't work.
However I just can't seem to get the proper result still (all that is rendered to the shadow map is the cube, which seems rather elongated at that).
Maybe it is that I've missed something after staring blind at these things for days and nights so I post my code here for anyone who feels up to it to investigate and try out.
---------------------------------------------------
main.cpp
The main source file.
int main(char* argv[], int argc) {
if(!initDarkGDK("gdkengine.dll"))
return 1;
HWND hwnd = openWindow(0, 0, 1024, 768, "RenderWindow", 382205952, true);
dbOpenScreen(hwnd, 0, 0, 1024, 768, 32);
ShowWindow(hwnd, SW_SHOW);
// From here it's basically a direct port of Fallout's example, save that I just added the content
// of the Init function here at the beginning
int objFloor = 1, objSphere = 2, objCube = 3, objLight = 4;
int imgObjTex = 1, imgLightTex = 2, imgDepthTex = 3;
int depthMapResolution = 1024;
dbSetDisplayMode(1024, 768, 32);
dbAutoCamOff();
dbSyncRate(60);
// Create object texture
dbCreateBitmap(512, 512, 1);
for(int x = 0; x < 512; x++)
for(int y = 0; y < 512; y++)
dbDot(x, y, dbRGB(x / 2, y / 2, (x + y) / 2));
dbGetImage(0, 0, 511, 511, 0, imgObjTex);
// Create texture for the light object
for(int x = 0; x < 512; x++)
for(int y = 0; y < 512; y++)
dbDot(x, y, dbRGB(255, 255, 0));
dbGetImage(0, 0, 511, 511, 0, imgLightTex);
dbDeleteBitmap(1);
dbSetCurrentBitmap(0);
// Load shader
dbLoadEffect("SimpleShadow.dbs", 0, 1, 1);
// Create objects and apply base textures
dbCreateObjectPlane(20.0f, 20.0f, 0, objFloor); dbTextureObject(objFloor, imgObjTex); dbXRotateObject(objFloor, 270.0f);
dbCreateObjectSphere(2.0f, 12, 12, objSphere); dbTextureObject(objSphere, imgObjTex);
dbCreateObjectCube(2.0f, objCube); dbTextureObject(objCube, imgObjTex);
dbCreateObjectSphere(1.0f, 12, 12, objLight); dbTextureObject(objLight, imgLightTex);
// Apply shader to the objects
dbSetObjectEffect(objFloor, 1);
dbSetObjectEffect(objSphere, 1);
dbSetObjectEffect(objCube, 1);
// Create depth texture rendering camera
dbCreateCamera(1); dbSetCameraRange(1.0f, 80.0f, 1); dbSetCameraFOV(130.0f, 1); dbColorBackdrop(dbRGB(255, 0, 0), 1);
// Create and set up rendering to our depth map texture
dbCreateBitmap(depthMapResolution, depthMapResolution, 1);
dbGetImage(0, 0, depthMapResolution - 1, depthMapResolution - 1, 0, imgDepthTex);
dbSetCameraToImage(1, imgDepthTex, depthMapResolution, depthMapResolution);
dbDeleteBitmap(1);
// Apply this image as the depth map texture for all of our shadowed objects
dbTextureObject(objFloor, imgDepthTex, 1);
dbTextureObject(objSphere, imgDepthTex, 1);
dbTextureObject(objCube, imgDepthTex, 1);
dbSetCurrentBitmap(0);
// Create some matrices which we'll use for storing the light's view
gdk::Matrix4 matrix1, matrix2, matrix3;
// Main Loop
do {
// Move objects / perform "game" logic
dbPositionObject(objSphere, 0.0f, 6.0f + dbSin(clock() / 10.0f) * 4, 0.0f);
dbPositionObject(objCube, dbSin(clock() / 15.0f) * 10, 2 + dbSin(clock() / 20.0f), 5.0f);
// Position our shadow light source and calculate a projection matrix for it
dbPositionObject(objLight, 0.0f, 12.0f, dbSin(clock() / 10.0f) * 10);
dbPositionCamera(dbObjectPositionX(objLight), dbObjectPositionY(objLight), dbObjectPositionZ(objLight), 1);
dbPointCamera(0.0f, 0.0f, 0.0f, 1); // View the "world" / scene
// Create the matrix
dbSetCurrentCamera(1);
matrix1.setViewMatrix();
matrix2.setProjectionMatrix();
matrix1.multiply(matrix2, &matrix3);
std::cout << "Light Projection Matrix:\n" << matrix3 << "\n";
// Render the scene / "world" from the light source's point of view
dbSetEffectTechnique(1, "GetDepth");
dbSetEffectConstantMatrixInternal(1, "LightProjMatrix", matrix3.pushInternal());
dbSetEffectConstantFloat(1, "ShadowAdjust", 0.01f);
dbSyncMask(2); dbSync(true); // Only render the depth camera
dbSetCurrentCamera(0); // Return to our normal camera
// Allow pasting of the depth map by holding down the return key
if(dbReturnKey() != 0)
dbPasteImage(imgDepthTex, 0, 0);
// Render the scene "normally" (including the depth map data)
dbSetEffectTechnique(1, "NormalRender");
// Position main camera
dbPositionCamera(0.0f, 0.0f, 0.0f);
dbXRotateCamera(45.0f);
dbYRotateCamera(dbWrapValue(dbCameraAngleY() + 0.1f));
dbMoveCamera(-30.0f);
// Render
dbSyncMask(1); dbSync();
} while(windowEvent() != WM_CLOSE && !dbKeyState(VK_ESCAPE));
return 0;
}
MathWrapper.h
Just contains some typedefs to discern the internal DGDK Vector / Matrix structs from my own wrapper classes.
#pragma once
#include <include/dgdk/core/darkgdk.h>
// Define some alternative typedefs for names that wil otherwise clash with our own classes such as Vector4, etc.
typedef Vector2 dbVector2;
typedef Vector3 dbVector3;
typedef Vector4 dbVector4;
typedef Matrix4 dbMatrix4;
Matrix4.h
Wraps the underlying calls to the DirectX functions used by DarkBasic's 3D math functions. Also extends this by keeping an internal "standard" DBP matrix4 (referred to by ID). This is used when communicating with shaders.
#pragma once
#include "MathWrapper.h"
#include <d3d9.h>
#include <d3dx9math.h>
namespace gdk {
// Forward declaraions
class Vector3;
class Matrix4 : public dbMatrix4 {
private:
static int32_t _internalID;
public:
Matrix4() {
}
Matrix4(const Matrix4 &other) {
// Can't be bothered to do this properly right now; it is doubtful whether it'll be used often (if at all) anyway
x1 = other.x1; x2 = other.x2; x3 = other.x3; x4 = other.x4;
y1 = other.y1; y2 = other.y2; y3 = other.y3; y4 = other.y4;
z1 = other.z1; z2 = other.z2; z3 = other.z3; z4 = other.z4;
w1 = other.w1; w2 = other.w2; w3 = other.w3; w4 = other.w4;
}
~Matrix4() {
}
bool operator==(const Matrix4 &other) {
return x1 == other.x1 && x2 == other.x2 && x3 == other.x3 && x4 == other.x4 &&
y1 == other.y1 && y2 == other.y2 && y3 == other.y3 && y4 == other.y4 &&
z1 == other.z1 && z2 == other.z2 && z3 == other.z3 && z4 == other.z4 &&
w1 == other.w1 && w2 == other.w2 && w3 == other.w3 && w4 == other.w4;
}
inline Matrix4* add(Matrix4 &other, Matrix4 *pResult = NULL) {
if(!pResult)
pResult = this;
pResult->x1 = x1 + other.x1;
pResult->x2 = x2 + other.x2;
pResult->x3 = x3 + other.x3;
pResult->x4 = x4 + other.x4;
pResult->y1 = y1 + other.y1;
pResult->y2 = y2 + other.y2;
pResult->y3 = y3 + other.y3;
pResult->y4 = y4 + other.y4;
pResult->z1 = z1 + other.z1;
pResult->z2 = z2 + other.z2;
pResult->z3 = z3 + other.z3;
pResult->z4 = z4 + other.z4;
pResult->w1 = w1 + other.w1;
pResult->w2 = w2 + other.w2;
pResult->w3 = w3 + other.w3;
pResult->w4 = w4 + other.w4;
return pResult;
}
inline Matrix4* subtract(Matrix4 &other, Matrix4 *pResult = NULL) {
if(!pResult)
pResult = this;
pResult->x1 = x1 - other.x1;
pResult->x2 = x2 - other.x2;
pResult->x3 = x3 - other.x3;
pResult->x4 = x4 - other.x4;
pResult->y1 = y1 - other.y1;
pResult->y2 = y2 - other.y2;
pResult->y3 = y3 - other.y3;
pResult->y4 = y4 - other.y4;
pResult->z1 = z1 - other.z1;
pResult->z2 = z2 - other.z2;
pResult->z3 = z3 - other.z3;
pResult->z4 = z4 - other.z4;
pResult->w1 = w1 - other.w1;
pResult->w2 = w2 - other.w2;
pResult->w3 = w3 - other.w3;
pResult->w4 = w4 - other.w4;
return pResult;
}
inline Matrix4* multiply(Matrix4 &other, Matrix4 *pResult = NULL) {
if(!pResult)
pResult = this;
D3DXMatrixMultiply((D3DXMATRIX*)pResult, (D3DXMATRIX*)this, (D3DXMATRIX*)&other);
return pResult;
}
inline Matrix4* multiplyScalar(float value) {
x1 *= value;
x2 *= value;
x3 *= value;
x4 *= value;
y1 *= value;
y2 *= value;
y3 *= value;
y4 *= value;
z1 *= value;
z2 *= value;
z3 *= value;
z4 *= value;
w1 *= value;
w2 *= value;
w3 *= value;
w4 *= value;
return this;
}
inline Matrix4* divide(float value) {
x1 /= value;
x2 /= value;
x3 /= value;
x4 /= value;
y1 /= value;
y2 /= value;
y3 /= value;
y4 /= value;
z1 /= value;
z2 /= value;
z3 /= value;
z4 /= value;
w1 /= value;
w2 /= value;
w3 /= value;
w4 /= value;
return this;
}
inline Matrix4* inverse(Matrix4 *pResult = NULL) {
if(!pResult)
pResult = this;
D3DXMatrixInverse((D3DXMATRIX*)pResult, NULL, (D3DXMATRIX*)this); // The DB one doesn't use any determinant I think?
return pResult;
}
inline bool isIdentityMatrix() const {
return D3DXMatrixIsIdentity((D3DXMATRIX*)this) == TRUE ? true : false;
}
inline void setIdentityMatrix() {
D3DXMatrixIdentity((D3DXMATRIX*)this);
}
// TODO: These probably rather belong to the Camera class, ie. Camera::getProjectionMatrix()
inline void setProjectionMatrix() {
dbProjectionMatrix4(this);
}
inline void setViewMatrix() {
// TODO: SAME AS THE ABOVE
dbViewMatrix4(this);
}
inline void setWorldMatrix() {
// TODO: SAME AS THE ABOVE
dbWorldMatrix4(this);
}
inline void buildFOVLHMatrix(float fov, float aspect, float nearRange, float farRange) {
D3DXMatrixPerspectiveFovLH((D3DXMATRIX*)this, fov, aspect, nearRange, farRange);
}
inline void buildFOVRHMatrix(float fov, float aspect, float nearRange, float farRange) {
D3DXMatrixPerspectiveFovRH((D3DXMATRIX*)this, fov, aspect, nearRange, farRange);
}
// Can't be defined here as it requires Vector3 references, which in turn require Matrix4 references
void buildLookAtLHMatrix(Vector3 &vector3Eye, Vector3 &vector3At, Vector3 &vector3Up);
void buildLookAtRHMatrix(Vector3 &vector3Eye, Vector3 &vector3At, Vector3 &vector3Up);
void buildRotationAxisMatrix(Vector3 &axis, float angle);
inline void buildOrthoLHMatrix(float width, float height, float nearRange, float farRange) {
D3DXMatrixOrthoLH((D3DXMATRIX*)this, width, height, nearRange, farRange);
}
inline void buildOrthoRHMatrix(float width, float height, float nearRange, float farRange) {
D3DXMatrixOrthoRH((D3DXMATRIX*)this, width, height, nearRange, farRange);
}
inline void buildPerspectiveLHMatrix(int width, int height, float nearRange, float farRange) {
D3DXMatrixPerspectiveLH((D3DXMATRIX*)this, (float)width, (float)height, nearRange, farRange);
}
inline void buildPerspectiveRHMatrix(int width, int height, float nearRange, float farRange) {
D3DXMatrixPerspectiveRH((D3DXMATRIX*)this, (float)width, (float)height, nearRange, farRange);
}
inline void buildReflectionMatrix(float planeA, float planeB, float planeC, float planeD) {
D3DXMatrixReflect((D3DXMATRIX*)this, &(D3DXPLANE(planeA, planeB, planeC, planeD)));
}
inline void translate(float x, float y, float z) {
D3DXMatrixTranslation((D3DXMATRIX*)this, x, y, z);
}
inline void scale(float x, float y, float z) {
D3DXMatrixScaling((D3DXMATRIX*)this, x, y, z);
}
inline void rotateX(float angle) {
D3DXMatrixRotationX((D3DXMATRIX*)this, angle);
}
inline void rotateY(float angle) {
D3DXMatrixRotationY((D3DXMATRIX*)this, angle);
}
inline void rotateZ(float angle) {
D3DXMatrixRotationZ((D3DXMATRIX*)this, angle);
}
inline void rotateYPR(float yaw, float pitch, float roll) {
D3DXMatrixRotationYawPitchRoll((D3DXMATRIX*)this, yaw, pitch, roll);
}
inline void transpose(Matrix4 *pResult = NULL) {
if(!pResult)
pResult = this;
D3DXMatrixTranspose((D3DXMATRIX*)pResult, (D3DXMATRIX*)this);
}
int32_t pushInternal();
};
}
// Allow printing of the contents to a ostream in a quick and simple fashion
inline std::ostream& operator<<(std::ostream &out, gdk::Matrix4 const &m) {
out << "[\t" << m.x1 << "\t" << m.x2 << "\t" << m.x3 << "\t" << m.x4 << "\n\t" <<
m.y1 << "\t" << m.y2 << "\t" << m.y3 << "\t" << m.y4 << "\n\t" <<
m.z1 << "\t" << m.z2 << "\t" << m.z3 << "\t" << m.z4 << "\n\t" <<
m.w1 << "\t" << m.w2 << "\t" << m.w3 << "\t" << m.w4 << "]";
return out;
}
Matrix4.cpp
While most member functions are inlined and present in Matrix4.h due to their simple wrapping nature, this file contains some functions that cannot be inlined due to cross references between Matrix4.h and Vector3.h as well as initiation of static fields.
#include "Matrix4.h"
#include "Vector3.h"
#include <iostream>
using namespace gdk;
void gdk::Matrix4::buildLookAtLHMatrix(Vector3 &vector3Eye, Vector3 &vector3At, Vector3 &vector3Up) {
D3DXMatrixLookAtLH((D3DXMATRIX*)this, (D3DXVECTOR3*)&vector3Eye, (D3DXVECTOR3*)&vector3At, (D3DXVECTOR3*)&vector3Up);
}
void gdk::Matrix4::buildLookAtRHMatrix(Vector3 &vector3Eye, Vector3 &vector3At, Vector3 &vector3Up) {
D3DXMatrixLookAtRH((D3DXMATRIX*)this, (D3DXVECTOR3*)&vector3Eye, (D3DXVECTOR3*)&vector3At, (D3DXVECTOR3*)&vector3Up);
}
void gdk::Matrix4::buildRotationAxisMatrix(Vector3 &axis, float angle) {
D3DXMatrixRotationAxis((D3DXMATRIX*)this, (D3DXVECTOR3*)&axis, angle);
}
int32_t gdk::Matrix4::pushInternal() {
if(!_internalID) {
_internalID = 9;
int32_t res = dbMakeInternalMatrix4(_internalID);
}
dbSetInternalMatrix4(_internalID, x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4, w1, w2, w3, w4);
//std::cout << "Local matrix: \n" << *this << "\n\nInternal Matrix set to: \n";
//for(int r = 0; r < 4; r++) {
// for(int c = 0; c < 4; c++)
// std::cout << dbGetInternalMatrix4Element(_internalID, (r * 4) + c) << '\t';
// std::cout << '\n';
//}
// NOTE: Yes, they seem to indeed be set to the same values
return _internalID;
}
// Static initialisation
int32_t gdk::Matrix4::_internalID = 0;
The below file isn't really used in the example code but it is included by Matrix4.cpp so it's here for completeness. You can just outcomment the functions using it in Matrix4.cpp and everything should likely work.
Vector3.h
#pragma once
#include "MathWrapper.h"
#include <d3d9.h>
#include <d3dx9math.h>
namespace gdk {
class Vector3 : public dbVector3 {
public:
// NOTE: The internal DGDK Vector structs must be updated with a constructor to set the initial values as well
Vector3(float fX = 0.0f, float fY = 0.0f, float fZ = 0.0f) : dbVector3(fX, fY, fZ) {
}
Vector3(const Vector3& other) : dbVector3(other.x, other.y, other.z) {
}
~Vector3() {
// No particular clean-up needs to be performed
}
bool operator==(const Vector3& other) {
return x == other.x && y == other.y && z == other.z;
}
// TODO: Consider implementing the simple operators manually rather than calling a dll for ie. vector addition
// Cannot use const-correctness below since the wrapped functions doesn't
inline Vector3& add(Vector3 &other, Vector3 *pResult = NULL) {
if(!pResult)
pResult = this;
D3DXVec3Add((D3DXVECTOR3*)pResult, (D3DXVECTOR3*)this, (D3DXVECTOR3*)&other);
return *pResult;
}
inline Vector3& subtract(Vector3 &other, Vector3 *pResult = NULL) {
if(!pResult)
pResult = this;
D3DXVec3Subtract((D3DXVECTOR3*)pResult, (D3DXVECTOR3*)this, (D3DXVECTOR3*)&other);
return *pResult;
}
inline Vector3& multiply(float factor) {
// This is just simple scalar multiplication; should probably be overloaded as operator* as well
x *= factor;
y *= factor;
z *= factor;
return *this;
}
inline Vector3& divide(float factor) {
// This is just simple scalar division; should probably be overloaded as operator/ as well
x /= factor;
y /= factor;
z /= factor;
return *this;
}
inline Vector3& crossProduct(Vector3 &other, Vector3 *pResult = NULL) {
if(!pResult)
pResult = this;
D3DXVec3Cross((D3DXVECTOR3*)pResult, (D3DXVECTOR3*)this, (D3DXVECTOR3*)&other);
return *pResult;
}
inline float getLength() {
return D3DXVec3Length((D3DXVECTOR3*)this);
}
inline float getSquaredLength() {
return D3DXVec3LengthSq((D3DXVECTOR3*)this);
}
inline float dotProduct(Vector3 &other) {
return D3DXVec3Dot((D3DXVECTOR3*)this, (D3DXVECTOR3*)(&other));
}
inline Vector3& maximize(Vector3 &other, Vector3 *pResult = NULL) {
if(!pResult)
pResult = this;
D3DXVec3Maximize((D3DXVECTOR3*)pResult, (D3DXVECTOR3*)this, (D3DXVECTOR3*)&other);
return *pResult;
}
inline Vector3& minimize(Vector3 &other, Vector3 *pResult = NULL) {
if(!pResult)
pResult = this;
D3DXVec3Minimize((D3DXVECTOR3*)pResult, (D3DXVECTOR3*)this, (D3DXVECTOR3*)&other);
return *pResult;
}
inline Vector3& normalize(Vector3 *pResult = NULL) {
if(!pResult)
pResult = this;
D3DXVec3Normalize((D3DXVECTOR3*)pResult, (D3DXVECTOR3*)this);
return *pResult;
}
inline Vector3& scale(float value, Vector3 *pResult = NULL) {
if(!pResult)
pResult = this;
D3DXVec3Scale((D3DXVECTOR3*)pResult, (D3DXVECTOR3*)this, value);
return *pResult;
}
inline void transformCoords(Matrix4 &srcMatrix, Vector3 *pResult = NULL) {
if(!pResult)
pResult = this;
D3DXVec3TransformCoord((D3DXVECTOR3*)pResult, (D3DXVECTOR3*)this, (D3DXMATRIX*)&srcMatrix);
}
inline void transformNormals(Matrix4 &srcMatrix, Vector3 *pResult = NULL) {
if(!pResult)
pResult = this;
D3DXVec3TransformNormal((D3DXVECTOR3*)pResult, (D3DXVECTOR3*)this, (D3DXMATRIX*)&srcMatrix);
}
inline void project(Matrix4 &projectionMatrix, Matrix4 &viewMatrix, Matrix4 &worldMatrix, Vector3 *pResult = NULL) {
if(!pResult)
pResult = this;
dbProjectVector3(pResult, this, &projectionMatrix, &viewMatrix, &worldMatrix);
D3DVIEWPORT9 pViewport;
gdk::getDirect3DDevice()->GetViewport(&pViewport);
D3DXVec3Project((D3DXVECTOR3*)pResult, (D3DXVECTOR3*)this, &pViewport,
(D3DXMATRIX*)&projectionMatrix, (D3DXMATRIX*)&viewMatrix, (D3DXMATRIX*)&worldMatrix);
}
// Convenience method for simultaneous setting of all coordinates without having to create a new Vector
inline void set(float fX, float fY, float fZ) {
x = fX;
y = fY;
z = fZ;
}
static Vector3* BCC(Vector3 &vectorA, Vector3 &vectorB, Vector3 &vectorC, float fValue, float gbValue,
Vector3 *pResult = NULL) {
if(!pResult)
pResult = new Vector3();
D3DXVec3BaryCentric((D3DXVECTOR3*)pResult, (D3DXVECTOR3*)&vectorA, (D3DXVECTOR3*)&vectorB, (D3DXVECTOR3*)&vectorC,
fValue, gbValue);
return pResult;
}
static Vector3* CatmullRom(Vector3 &vectorA, Vector3 &vectorB, Vector3 &vectorC, Vector3 &vectorD, float value,
Vector3 *pResult = NULL) {
if(!pResult)
pResult = new Vector3();
D3DXVec3CatmullRom((D3DXVECTOR3*)pResult, (D3DXVECTOR3*)&vectorA, (D3DXVECTOR3*)&vectorB, (D3DXVECTOR3*)&vectorC,
(D3DXVECTOR3*)&vectorD, value);
return pResult;
}
static Vector3* Hermite(Vector3 &vectorA, Vector3 &vectorB, Vector3 &vectorC, Vector3 &vectorD, float sValue,
Vector3 *pResult = NULL) {
if(!pResult)
pResult = new Vector3();
D3DXVec3Hermite((D3DXVECTOR3*)pResult, (D3DXVECTOR3*)&vectorA, (D3DXVECTOR3*)&vectorB, (D3DXVECTOR3*)&vectorC,
(D3DXVECTOR3*)&vectorD, sValue);
return pResult;
}
static Vector3* LinearInterpolate(Vector3 &vectorA, Vector3 &vectorB, float sValue, Vector3 *pResult = NULL) {
if(!pResult)
pResult = new Vector3();
D3DXVec3Lerp((D3DXVECTOR3*)pResult, (D3DXVECTOR3*)&vectorA, (D3DXVECTOR3*)&vectorB, sValue);
return pResult;
}
};
}
// Allow printing of the contents to a ostream in a quick and simple fashion
inline std::ostream& operator<<(std::ostream &out, gdk::Vector3 const &v) {
out << "(" << v.x << ", " << v.y << ", " << v.z << ")";
return out;
}
Now there are some additional dll functions required here. These are from
DBProVectorsDebug.dll and
Matrix1Util_32.dll. The latter must be manually included in your darkgdk.dll file by adding the following line to your
(DarkGDK)/engine/libraries file (yes it has no file extension):
Matrix1Util_32.dll%Matrix1Util 32
.
(Of course you must also drop the Matrix1Util_32.dll file in your
(DarkGDK)/engine/plugins-user folder).
The functions wrappers are as follows and goes (I suggest, but you can place them whereever) at the bottom of your
include/dgdk/core/dgdk-math.h and
dgdk-math.cpp files:
[ADD TO] dgdk-math.h
int32_t dbMakeInternalVector4(int32_t internalVectorID);
void dbSetInternalVector4(int32_t internalVectorID, float x, float y, float z, float w);
void dbDeleteInternalVector4(int32_t internalVectorID);
int32_t dbMakeInternalMatrix4(int32_t internalMatrixID);
void dbSetInternalMatrix4(int32_t internalMatrixID, float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4, float z1, float z2, float z3, float z4, float w1, float w2, float w3, float w4);
int32_t dbGetInternalDXMatrix(int32_t internalMatrixID);
float dbGetInternalMatrix4Element(int32_t internalMatrixID, int32_t element);
void dbDeleteInternalMatrix4(int32_t internalMatrixID);
void dbSetInternalIdentityMatrix(int32_t internalMatrixID);
[ADD TO] dgdk-math.cpp
typedef int32_t (__cdecl *ProtodbMakeInternalVector4_1)(int32_t internalVectorID);
int32_t dbMakeInternalVector4(int32_t internalVectorID) {
static ProtodbMakeInternalVector4_1 Ptr;
int32_t result = 0;
if (!Ptr && !GDKLoadPtr(&Ptr,"DBProVectorsDebug.dll","?MakeVector4@@YAHH@Z"))
return 0;
if (GDKWaitFunction()) {
result = Ptr(internalVectorID);
GDKCleanupFunctionCall();
}
return result;
}
typedef int32_t (__cdecl *ProtodbMakeInternalMatrix4_1)(int32_t internalMatrixID);
int32_t dbMakeInternalMatrix4(int32_t internalMatrixID) {
static ProtodbMakeInternalMatrix4_1 Ptr;
int32_t result = 0;
if (!Ptr && !GDKLoadPtr(&Ptr,"DBProVectorsDebug.dll","?MakeMatrix@@YAHH@Z"))
return 0;
if (GDKWaitFunction()) {
result = Ptr(internalMatrixID);
GDKCleanupFunctionCall();
}
return result;
}
typedef void (__cdecl *ProtodbSetInternalVector4_5)(int32_t internalVectorID, float x, float y, float z, float w);
void dbSetInternalVector4(int32_t internalVectorID, float x, float y, float z, float w) {
static ProtodbSetInternalVector4_5 Ptr;
if (!Ptr && !GDKLoadPtr(&Ptr,"DBProVectorsDebug.dll","?SetVector4@@YAXHMMMM@Z"))
return;
if (GDKWaitFunction()) {
Ptr(internalVectorID, x, y, z, w);
GDKCleanupFunctionCall();
}
return;
}
typedef void (__cdecl *ProtodbDeleteInternalVector4_1)(int32_t internalVectorID);
void dbDeleteInternalVector4(int32_t internalVectorID) {
static ProtodbDeleteInternalVector4_1 Ptr;
if (!Ptr && !GDKLoadPtr(&Ptr,"DBProVectorsDebug.dll","?DeleteVector4@@YAHH@Z"))
return;
if (GDKWaitFunction()) {
Ptr(internalVectorID);
GDKCleanupFunctionCall();
}
return;
}
typedef int32_t(__cdecl *ProtodbGetInternalDXMatrix_1)(int32_t internalMatrixID);
int32_t dbGetInternalDXMatrix(int32_t internalMatrixID) {
static ProtodbGetInternalDXMatrix_1 Ptr;
int32_t result = 0;
if (!Ptr && !GDKLoadPtr(&Ptr,"DBProVectorsDebug.dll","?GetMatrix@@YA?AUD3DXMATRIX@@H@Z"))
return 0;
if (GDKWaitFunction()) {
result = Ptr(internalMatrixID);
GDKCleanupFunctionCall();
}
return result;
}
typedef void (__cdecl *ProtodbDeleteInternalMatrix4_1)(int32_t internalMatrixID);
void dbDeleteInternalMatrix4(int32_t internalMatrixID) {
static ProtodbDeleteInternalMatrix4_1 Ptr;
if (!Ptr && !GDKLoadPtr(&Ptr,"DBProVectorsDebug.dll","?DeleteMatrix@@YAHH@Z"))
return;
if (GDKWaitFunction()) {
Ptr(internalMatrixID);
GDKCleanupFunctionCall();
}
return;
}
typedef void (__cdecl *ProtodbSetInternalMatrix4_17)(int32_t internalMatrixID, float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4, float z1, float z2, float z3, float z4, float w1, float w2, float w3, float w4);
void dbSetInternalMatrix4(int32_t internalMatrixID, float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4, float z1, float z2, float z3, float z4, float w1, float w2, float w3, float w4) {
static ProtodbSetInternalMatrix4_17 Ptr;
if (!Ptr && !GDKLoadPtr(&Ptr, "Matrix1Util_32.dll", "SetMatrix4")) {
MessageBoxA(0, "Failed to call SetMatrix", "", 16);
return;
}
if (GDKWaitFunction()) {
Ptr(internalMatrixID, x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4, w1, w2, w3, w4);
GDKCleanupFunctionCall();
}
return;
}
typedef int32_t (__cdecl *ProtodbGetInternalMatrix4Element_2)(int32_t internalMatrixID, int32_t element);
float dbGetInternalMatrix4Element(int32_t internalMatrixID, int32_t element) {
static ProtodbGetInternalMatrix4Element_2 Ptr;
float floatValue = 0.0f;
if (!Ptr && !GDKLoadPtr(&Ptr,"DBProVectorsDebug.dll","?GetMatrixElement@@YAKHH@Z"))
return floatValue;
int result = 0;
if (GDKWaitFunction()) {
result = Ptr(internalMatrixID, element);
floatValue = *(const float*)&result;
GDKCleanupFunctionCall();
}
return floatValue;
}
typedef void (__cdecl *ProtodbSetInternalIdentityMatrix_1)(int32_t internalMatrixID);
void dbSetInternalIdentityMatrix(int32_t internalMatrixID) {
static ProtodbSetInternalIdentityMatrix_1 Ptr;
if (!Ptr && !GDKLoadPtr(&Ptr, "DBProVectorsDebug.dll", "?SetIdentityMatrix@@YAXH@Z"))
return;
if (GDKWaitFunction()) {
Ptr(internalMatrixID);
GDKCleanupFunctionCall();
}
return;
}
EDIT: here's the shader source from Fallout's thread as well, refered to as
SimpleShadow.dbs in my main.cpp file above:
//------------------------------------------------
// Basic Shadow Shader, by Simon Keating (Fallout)
//------------------------------------------------
// A very basic shadow shader for you to build upon
// *********************************************************************************
// These are variable DBP passes into the shader for you. You add what you want here
// and they are automatically populated
// *********************************************************************************
matrix WorldVP : WorldViewProjection; // This matrix describes how the camera sees the object we're shading
matrix World : World; // This matrix describes how an object is translated in the world
matrix ViewMat={0.5,0,0,0.5,0,-0.5,0,0.5,0,0,0.5,0.5,0,0,0,1};
// ******************************************************************************
// These variables are ones we can pass in using the SET EFFECT CONSTANT commands
// ******************************************************************************
matrix LightProjMatrix; // This matrix describes how the light sees the object we're shading
float ShadowAdjust; // The variable helps sort out some self shading issues
// *********************************************************************************************
// This is where we define what textures are mapped to our object and how we'll sample from them
// *********************************************************************************************
texture Texture1 <string Name="";>; // This says we'll expect a texture at LAYER 0. Our BASE texture!
sampler2D BaseTexure = sampler_state { // This creates a sampler which will read from this texture
Texture = <Texture1>;
};
texture Texture2 <string Name="";>; // This says we'll expect a texture at LAYER 1. The DEPTH texture.
sampler2D DepthTexture = sampler_state { // This creates a sampler which will read from this texture
Texture = <Texture2>;
};
// ******************************************************************************
// These are structures which define what goes in and out of our shader functions
// ******************************************************************************
// This data structure goes into our VERTEX SHADER when we're rendering depth
struct IN_DepthRender
{
float4 VertexPosition : POSITION;
};
// This structure comes out of our depth VERTEX SHADER and goes into our depth PIXEL SHADER
struct OUT_DepthRender
{
float4 VertexPosition : POSITION;
float DistanceFromLight : TEXCOORD0;
};
// This data structure goes into our VERTEX SHADER when we're rendering normally
struct IN_NormalRender
{
float4 VertexPosition : POSITION;
float2 VertexUVCoords : TEXCOORD0;
};
// This structure comes out of our normal VERTEX SHADER and goes into our normal PIXEL SHADER
struct OUT_NormalRender
{
float4 VertexPosition : POSITION;
float2 VertexUVCoords : TEXCOORD0;
float4 LightVertexPosition : TEXCOORD1;
};
//******************************************************************************
// This is our vertex and pixel shader code. This is where all the magic happens
//******************************************************************************
// ---------DEPTH-----------
OUT_DepthRender VS_Depth(IN_DepthRender IN)
{
OUT_DepthRender OUT;
float4 WorldVertexPosition = mul(IN.VertexPosition,World); // Work out how the object vertex is positioned in the world
float4 LightProjectionVertexPosition = mul(WorldVertexPosition,LightProjMatrix); // Work out how the light sees this vertex
OUT.VertexPosition = LightProjectionVertexPosition; // Save how our light views this vertex to our output
OUT.DistanceFromLight = LightProjectionVertexPosition.z; // Save the depth of this vertex position to our output
return OUT;
}
float4 PS_Depth(OUT_DepthRender IN) : COLOR
{
// The pixel shader takes values from our vertex shader.
// Calculate a red colour from our vertex depth. This is what you see on screen
return float4(smoothstep(0,30,IN.DistanceFromLight+0.2),0,0,1);
}
// ---------NORMAL RENDER-----------
OUT_NormalRender VS_Normal(IN_NormalRender IN)
{
OUT_NormalRender OUT;
OUT.VertexPosition = mul(IN.VertexPosition, WorldVP); // Work out how the normal camera views our vertex
float4 WorldVertexPosition = mul(IN.VertexPosition, World); // Work out how the vertex is positioned in the world
float4 LightVertexPosition = mul(WorldVertexPosition, LightProjMatrix); // Work out how the light sees this vertex
OUT.LightVertexPosition = mul(ViewMat, LightVertexPosition); // Modulate with view matrix and save to output
OUT.VertexUVCoords = IN.VertexUVCoords; // The pixel shader will also need the UV coordinates!
return OUT;
}
float4 PS_Normal(OUT_NormalRender IN) : COLOR
{
// The pixel shader takes values from our vertex shader.
// The smoothstep function helps us get a nice smooth value when calculate how far this pixel is away from the light source
float DistanceFromLight = smoothstep(0,30,IN.LightVertexPosition.z);
float Darkness = 1;
// The tex2Dproj function is the key function. It converts the position of the pixel in terms of how the light sees it
// into a UV coordinate on the depth texture (rendered earlier). We can then compare the Z component (depth) of that texture
// coordinate to the distance of our pixel from the normal camera. If the pixel on the depth texture is closer to the light
// source than the pixel in the normal render is to the light source, we know the pixel is in shadow, so shade it black!
if (tex2Dproj(DepthTexture,IN.LightVertexPosition).r < DistanceFromLight - ShadowAdjust) Darkness = 0.5;
return tex2D(BaseTexure,IN.VertexUVCoords)*Darkness; // Look up the color from the base texture and shade it.
}
//--------------
// techniques
//--------------
technique GetDepth
{
pass p0
{
VertexShader = compile vs_2_0 VS_Depth();
PixelShader = compile ps_2_0 PS_Depth();
}
}
technique NormalRender
{
pass p0
{
VertexShader = compile vs_2_0 VS_Normal();
PixelShader = compile ps_2_0 PS_Normal();
}
}
Thanks for any help and fresh eyes,
Rudolpho
"Why do programmers get Halloween and Christmas mixed up?" Because Oct(31) = Dec(25)