Added CosmicGL.

This commit is contained in:
TempleProgramming 2021-06-26 04:10:21 -04:00
parent 9a30b7f1a0
commit 1cbc72e57b
34 changed files with 4329 additions and 1 deletions

View file

@ -15,7 +15,7 @@ Features in development include:
- Fully-functional AHCI support
- ~~VBE support~~ 32-bit color VBE graphics
- A new GUI framework in 32-bit color
- [Gr2](https://github.com/TempleProgramming/Gr2)
- CosmicGL renderer
- Compiler optimizations for speed improvements
- SSE2+ instruction support in compiler and assembler
- Network card drivers and a networking stack

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,83 @@
/* This demo renders a BSP. Put DOOM1.WAD in the directory to try this. */
Cd(__DIR__);;
"\n\n\n\n"; // Seperate from annoying warnings
I64 wWC = 90; // Window width in columns
I64 wHC = 90; // Window height in rows
I64 wW = wWC * 8;
I64 wH = wHC * 8;
I64 wXC = 1; // Window x in columns
I64 wYC = 2; // Window y in rows
I64 wX = wXC * 8;
I64 wY = wYC * 8;
SettingsPush;
WinHorz(wXC, wXC + wWC - 1);
WinVert(wYC, wYC + wHC - 1);
DocClear;
// Prepare framebuffer
CTex2D frameBuf;
Tex2DInit(&frameBuf, TEX2D_RAW, wW, wH);
Tex2DColorFill(&frameBuf, gr_palette[WHITE]);
// Load BSP and render
CWAD doom1;
WADLoad(&doom1, "DOOM1.WAD");
CDoomMap map;
DoomMapLoad(&map, &doom1, "E1M1");
// Sprite loading
CTex2D sprite;
Tex2DLoadWADSprite(&sprite, &doom1, "POSSF2F8");
WADFree(&doom1);
CBGR24 cRed;
cRed.r = 255; cRed.b = cRed.g = 0;
I64 i, a, b, c, d;
for (i = 0; i < map.nLines; i++)
{
a = map.lines[i].v1->x >> 32;
b = map.lines[i].v1->y >> 32;
c = map.lines[i].v2->x >> 32;
d = map.lines[i].v2->y >> 32;
a /= 8;
b /= 8;
c /= 8;
d /= 8;
a += 200;
b += 650;
c += 200;
d += 650;
if (a < 0 || b < 0 || c < 0 || d < 0 ||
a >= wW || b >= wH || c >= wW || d >= wH)
{
// One coordinate outside window
}
else
{
DrawLine(&frameBuf, a, b, c, d, cRed);
}
}
DrawTexture(&frameBuf, &sprite, 200, 200, TRUE);
while (CharScan() == 0)
{
Tex2DDebugDisp(&frameBuf, wX, wY);
Sleep(1);
}
DoomMapFree(&doom1);
Tex2DFree(&sprite);
Tex2DFree(&framebuf);
SettingsPop;
Exit;

View file

@ -0,0 +1,53 @@
/* This demo shows how to draw primitives to textures. */
Cd(__DIR__);;
I64 wWC = 64; // Window width in columns (512px)
I64 wHC = 48; // Window height in rows (384px)
I64 wW = wWC * 8;
I64 wH = wHC * 8;
I64 wXC = 1; // Window x in columns
I64 wYC = 2; // Window y in rows
I64 wX = wXC * 8;
I64 wY = wYC * 8;
SettingsPush;
WinHorz(wXC, wXC + wWC - 1);
WinVert(wYC, wYC + wHC - 1);
DocClear;
// Prepare framebuffer
CTex2D frameBuf;
Tex2DInit(&frameBuf, TEX2D_RAW, wW, wH);
Tex2DColorFill(&frameBuf, gr_palette[WHITE]);
// Draw Rectangles
DrawRectFill(&frameBuf, 32, 32, 128, 96, gr_palette[CYAN]);
DrawRectVertGradient(&frameBuf, 64, 128, 96, 256, gr_palette[CYAN],
gr_palette[BLUE]);
// Gradient's starting transition points can also be modified:
DrawRectVertGradient(&frameBuf, 160, 32, 224, 96, gr_palette[BLACK],
gr_palette[WHITE], 0.65, 0.7);
DrawRectOutline(&frameBuf, 55, 300, 75, 310, gr_palette[LTGRAY]);
// You can also define a second color for adding button-like shading
DrawRectSoftOutline(&frameBuf, 100, 200, 130, 210, gr_palette[LTGRAY],
gr_palette[DKGRAY]);
// Drawing text
DrawChar(&frameBuf, 48, 48, '!', gr_palette[WHITE]);
DrawString(&frameBuf, 16, 104, "When I wrote this, God said:
calls singing moist days excellence.", gr_palette[GREEN]);
while (CharScan() == 0)
{
Tex2DDebugDisp(&frameBuf, wX, wY);
Sleep(1);
}
Tex2DFree(&frameBuf);
SettingsPop;
Exit;

Binary file not shown.

View file

@ -0,0 +1,247 @@
/* This demo shows how to load a custom model (created based on the .obj format
using a converstion script). It uses WAD textures rather than BMP textures
unlike most of the other demos. The model is not transformed in any way and
is rendered directly, so scaling the window will also scale the resulting
render. */
Cd(__DIR__);;
I64 wWC = 80; // Window width in columns (Drop to under 80 for 640x480 displays)
I64 wHC = 45; // Window height in rows (Drop to under 60 for 640x480 displays)
I64 wW = wWC * 8;
I64 wH = wHC * 8;
I64 wXC = 1; // Window x in columns
I64 wYC = 2; // Window y in rows
I64 wX = wXC * 8;
I64 wY = (wYC + 0) * 8;
SettingsPush;
WinHorz(wXC, wXC + wWC - 1);
WinVert(wYC, wYC + wHC - 1);
DocClear;
// Framebuffer Initialization
CTex2D frameBuf;
CTex2D depthBuf;
Tex2DInit(&frameBuf, TEX2D_RAW, wW, wH);
Tex2DInit(&depthBuf, TEX2D_DEPTH, wW, wH);
// Colors
CBGR24 cBlack;
cBlack.r = 0; cBlack.g = 0; cBlack.b = 0;
CBGR24 cRed;
cRed.r = 255; cRed.g = 20; cRed.b = 20;
CBGR24 cWhite;
cWhite.r = 255; cWhite.g = 255; cWhite.b = 255;
Tex2DColorFill(&frameBuf, cBlack);
// Texture Intitalization
CWAD wad;
WADLoad(&wad, "KingTerry.wad");
CTex2D TexRevelation;
Tex2DLoadWAD(&TexRevelation, &wad, "Revelation");
CTex2D TexKingTerrySkin;
Tex2DLoadWAD(&TexKingTerrySkin, &wad, "KingTerry_Skin");
CTex2D TexKingTerryBody;
Tex2DLoadWAD(&TexKingTerryBody, &wad, "KingTerry_Body");
CTex2D TexNebula;
Tex2DLoadWAD(&TexNebula, &wad, "Nebula");
WADFree(&wad);
// Generate our own page texture
CTex2D TexPages;
Tex2DInit(&TexPages, TEX2D_RAW, 256, 256);
Tex2DColorFill(&TexPages, cWhite);
DrawString(&TexPages, 16, 20, "I should fix", cBlack);
DrawString(&TexPages, 16, 35, "the UVs on this", cBlack);
DrawString(&TexPages, 16, 50, "book model.", cBlack);
class CMat
{
U8 name[32];
U32 nOffset; // Offset to first triangle
U32 nTris; // Number of triangles
};
class CZMHeader
{
I32 nMats; // Number of materials
U32 nTriOffset; // Triangle array offset
U32 nVertOffset; // Vertex array offset
U32 nUVOffset; // UV array offset
U32 nNormOffset; // Normal array offset
};
class CZMTri
{
U32 iV1; // Vertices
U32 iV2;
U32 iV3;
U32 iN1; // Normals
U32 iN2;
U32 iN3;
U32 iT1; // UVs
U32 iT2;
U32 iT3;
};
class CZModel
{
CMat *mat;
CZMTri *tri;
CVec3 *vert;
CVec2 *uv;
CVec3 *norm;
};
class UniformTex
{
I64 mat; // Material index of model to render
CTex2D *tex;
};
class UniformCol
{
I64 mat;
CBGR24 col;
};
// Load model
U8 *MdlHandle = FileRead("TerryTruth.ZM");
CZMHeader *header = MdlHandle;
CZModel MdlTerry;
MdlTerry.mat = MdlHandle + 20;
MdlTerry.tri = MdlHandle + header->nTriOffset;
MdlTerry.vert = MdlHandle + header->nVertOffset;
MdlTerry.uv = MdlHandle + header->nUVOffset;
MdlTerry.norm = MdlHandle + header->nNormOffset;
// Prepare uniforms (unchanging parameters) to feed into shader
// Book cover is red
UniformCol UniCover;
UniCover.col.r = 150;
UniCover.col.g = 0;
UniCover.col.b = 0;
UniCover.mat = 0;
// Skin uses skin texture
UniformTex UniKingTerry_Skin;
UniKingTerry_Skin.tex = &TexKingTerrySkin;
UniKingTerry_Skin.mat = 1;
// Body uses body texture
UniformTex UniKingTerry_Body;
UniKingTerry_Body.tex = &TexKingTerryBody;
UniKingTerry_Body.mat = 2;
// Hat is black (dark gray)
UniformCol UniHat;
UniHat.col.r = 20;
UniHat.col.g = 20;
UniHat.col.b = 20;
UniHat.mat = 3;
// Pages uses WAD texture
UniformTex UniPages;
UniPages.tex = &TexPages; // Set this to &TexRevelation for original.
UniPages.mat = 4;
// Nebula uses WAD texture
UniformTex UniNebula;
UniNebula.tex = &TexNebula;
UniNebula.mat = 5;
// Generate a texure and color shader
CShader ShdTex, ShdCol;
ShdTex.vertValues = MAlloc(2 * sizeof(I64));
ShdTex.vertValues[0] = SHD_CVEC2; // UV
ShdTex.vertValues[1] = SHD_CVEC3; // Normal
ShdCol.vertValues = MAlloc(2 * sizeof(I64));
ShdCol.vertValues[0] = SHD_CVEC2; // UV
ShdCol.vertValues[1] = SHD_CVEC3; // Normal
ShdTex.nVertValues = 2;
ShdCol.nVertValues = 2;
U0 vShaderTex(CTri *tri, F64 *vertOutBuf, U8 *mdlPtr, U8 *uniforms, I64 iTri, I64 nTris)
{
CZModel *mdl = mdlPtr;
UniformTex *uni = uniforms;
nTris++; // So I don't have to see the unused warning.
I64 t = mdl->mat[uni->mat].nOffset + iTri; // Triangle index in triangle array
// Copy model directly into the triangle, I won't even transform for this demo.
MemCopy(&tri->p[0], &mdl->vert[mdl->tri[t].iV1 - 1], sizeof(CVec3));
MemCopy(&tri->p[1], &mdl->vert[mdl->tri[t].iV2 - 1], sizeof(CVec3));
MemCopy(&tri->p[2], &mdl->vert[mdl->tri[t].iV3 - 1], sizeof(CVec3));
tri->p[0].z = -1 * tri->p[0].z;
tri->p[1].z = -1 * tri->p[1].z;
tri->p[2].z = -1 * tri->p[2].z;
// Copy uv and normals into vertOutBuf to be interpolated for the vertex shader.
MemCopy(&vertOutBuf[0], &mdl->uv[mdl->tri[t].iT1 - 1], sizeof(CVec2));
MemCopy(&vertOutBuf[2], &mdl->norm[mdl->tri[t].iN1 - 1], sizeof(CVec3));
MemCopy(&vertOutBuf[5], &mdl->uv[mdl->tri[t].iT2 - 1], sizeof(CVec2));
MemCopy(&vertOutBuf[7], &mdl->norm[mdl->tri[t].iN2 - 1], sizeof(CVec3));
MemCopy(&vertOutBuf[10], &mdl->uv[mdl->tri[t].iT3 - 1], sizeof(CVec2));
MemCopy(&vertOutBuf[12], &mdl->norm[mdl->tri[t].iN3 - 1], sizeof(CVec3));
}
U0 fShaderTex(CBGR24 *color, F64 *fragInBuf, U8 *uniforms)
{
UniformTex *uni = uniforms;
Tex2DSampleNorm(color, uni->tex, fragInBuf[0], 1.0-fragInBuf[1]);
// Debug, display normals
// color->r=fragInBuf[2]*255.0; color->g=fragInBuf[3]*255.0; color->b=fragInBuf[4]*255.0;
}
U0 fShaderCol(CBGR24 *color, F64 *fragInBuf, U8 *uniforms)
{
UniformCol *uni = uniforms;
color->r = uni->col.r;
color->g = uni->col.g;
color->b = uni->col.b;
}
ShdTex.FragShd = &fShaderTex;
ShdTex.VertShd = &vShaderTex;
ShdCol.FragShd = &fShaderCol;
ShdCol.VertShd = &vShaderTex;
Tex2DDepthReset(&depthBuf);
RenderTris(&ShdCol, &frameBuf, &depthBuf, &MdlTerry, &UniCover, MdlTerry.mat[0].nTris);
RenderTris(&ShdTex, &frameBuf, &depthBuf, &MdlTerry, &UniKingTerry_Skin, MdlTerry.mat[1].nTris);
RenderTris(&ShdTex, &frameBuf, &depthBuf, &MdlTerry, &UniKingTerry_Body, MdlTerry.mat[2].nTris);
RenderTris(&ShdCol, &frameBuf, &depthBuf, &MdlTerry, &UniHat, MdlTerry.mat[3].nTris);
RenderTris(&ShdTex, &frameBuf, &depthBuf, &MdlTerry, &UniPages, MdlTerry.mat[4].nTris);
RenderTris(&ShdTex, &frameBuf, $ER$&depthBuf, &MdlTerry, &UniNebula, MdlTerry.mat[5].nTris);
while (CharScan() == 0)
{
Tex2DDebugDisp(&frameBuf, wX, wY);
Sleep(1);
}
Tex2DFree(&frameBuf);
Tex2DFree(&depthBuf);
Tex2DFree(&TexPages);
Tex2DFree(&TexRevelation);
Tex2DFree(&TexKingTerrySkin);
Tex2DFree(&TexKingTerryBody);
Tex2DFree(&TexNebula);
SettingsPop;
Exit;

Binary file not shown.

View file

@ -0,0 +1,30 @@
/* This demo shows how to initialize, import, and render textures. */
Cd(__DIR__);;
I64 wWC = 32; // Window width in columns (256px)
I64 wHC = 32; // Window height in rows (256px)
I64 wW = wWC * 8;
I64 wH = wHC * 8;
I64 wXC = 1; // Window x in columns
I64 wYC = 2; // Window y in rows
I64 wX = wXC * 8;
I64 wY = wYC * 8;
SettingsPush;
WinHorz(wXC, wXC + wWC - 1);
WinVert(wYC, wYC + wHC - 1);
DocClear;
CTex2D texture;
Tex2DLoadBMP(&texture, "SaintTerry.bmp");
while (CharScan() == 0)
{
Tex2DDebugDisp(&texture, wX, wY);
Sleep(1);
}
Tex2DFree(&texture);
SettingsPop;
Exit;

Binary file not shown.

After

(image error) Size: 192 KiB

Binary file not shown.

After

(image error) Size: 192 KiB

View file

@ -0,0 +1,119 @@
/* This demo shows how to create a custom model format, import a texture, and
program a shader to render a triangle. */
Cd(__DIR__);;
I64 wWC = 32; // Window width in columns (512px)
I64 wHC = 32; // Window height in rows (512px)
I64 wW = wWC * 8;
I64 wH = wHC * 8;
I64 wXC = 1; // Window x in columns
I64 wYC = 2; // Window y in rows
I64 wX = wXC * 8;
I64 wY = (wYC + 4) * 8;
SettingsPush;
WinHorz(wXC, wXC + wWC - 1);
WinVert(wYC, wYC + wHC + 3);
DocClear;
// Framebuffer Initialization
CTex2D frameBuf;
CTex2D depthBuf;
Tex2DInit(&frameBuf, TEX2D_RAW, wW, wH);
Tex2DInit(&depthBuf, TEX2D_DEPTH, wW, wH);
// Clear framebuffer texture with black background
CBGR24 cBlack;
cBlack.r = 0; cBlack.g = 0; cBlack.b = 0;
Tex2DColorFill(&frameBuf, cBlack);
// Importing BMP texture
CTex2D texture;
Tex2DLoadBMP(&texture, "MrGod.bmp");
// Create custom model format that is quite straightforward
class MDL
{
I64 nTris;
CTri *tri;
CVec2 *uv;
};
// Load it with a texture mapped triangle.
MDL model;
model.nTris = 1;
model.tri = MAlloc(sizeof(CTri));
model.tri[0].p[0].x = 0.0;
model.tri[0].p[0].y = 0.8;
model.tri[0].p[0].z = 0.0;
model.tri[0].p[1].x = -0.8;
model.tri[0].p[1].y = -0.4;
model.tri[0].p[1].z = 0.0;
model.tri[0].p[2].x = 0.8;
model.tri[0].p[2].y = -0.4;
model.tri[0].p[2].z = 0.0;
model.uv = MAlloc(sizeof(CVec2)*3);
// UVs commonly use coordinates of 0.0-1.0, although you can use direct pixel
// coordinates if you use the pixel coordinate sampler in the shader.
model.uv[0].x = 0.5;
model.uv[0].y = 0.0898;
model.uv[1].x = 0.07421875;
model.uv[1].y = 0.73046875;
model.uv[2].x = 0.9375;
model.uv[2].y = 0.7305;
// In this example a class is not needed for the uniforms (unchanging
// parameters), we only feed the pointer for the texture we want to sample.
// to the shader.
// Generate a shader. Each vertex has a UV coordinate (coordinate that
// maps to the texture), so we only need to pass one CVEC2 attribute
// from the vertex shader to the fragment shader.
CShader shd, shdB;
shd.vertValues = MAlloc(sizeof(I64));
shd.vertValues[0] = SHD_CVEC2; // UV coordinate
shd.nVertValues = 1;
// The vertex shader gives the normalized device coordinates (screen coordinates
// from -1.0 to 1.0) of each vertex of a specified triangle. Normally you would
// do translations and perspective transforms, but here our model is already in
// NDC. It also passes the UV coordinates of each vertex to the vertOutBuf to
// be interpolated for the fragment shader.
U0 vShader(CTri *tri, F64 *vertOutBuf, U8 *mdlPtr, U8 *uniforms, I64 iTri, I64 nTris)
{
MDL *mdl = mdlPtr;
MemCopy(tri, &mdl->tri[iTri], sizeof(CTri));
MemCopy(vertOutBuf, &mdl->uv[iTri*3], sizeof(CVec2)*3);
}
// The fragment shader calculates what color an individual fragment (pixel)
// should be. Here we use the interpolated UV coordinate from the fragInBuf to
// sample the color from the texture.
U0 fShader(CBGR24 *color, F64 *fragInBuf, U8 *uniforms)
{
// We will pass in the texture pointer through the uniform later
// when we render.
Tex2DSampleNorm(color, uniforms, fragInBuf[0], fragInBuf[1]);
}
// Attach vertex and fragment shader
shd.FragShd = &fShader;
shd.VertShd = &vShader;
while (CharScan() == 0)
{
// Where &texture is you would usually feed in a pointer to uniforms,
// however since the texture is the only value the shader needs,
// we simply pass in that pointer.
RenderTris(&shd, &frameBuf, &depthBuf, &model, &texture, 1);
Tex2DDebugDisp(&frameBuf, wX, wY);
Sleep(1);
}
Tex2DFree(&frameBuf);
Tex2DFree(&depthBuf);
Tex2DFree(&texture);
SettingsPop;
Exit;

10
src/Home/Registry.CC Normal file
View file

@ -0,0 +1,10 @@
$TR,"Zenith"$
$ID,2$$TR,"SysMessageFlags"$
$ID,2$sys_message_flags[0]=0;
$ID,-2$$TR,"SysRegVer"$
$ID,2$registry_version=2.010;
$ID,-2$$ID,-2$$TR,"Once"$
$ID,2$$TR,"Zenith"$
$ID,2$$ID,-2$$TR,"User"$
$ID,2$$ID,-2$$ID,-2$$TR,"AutoComplete"$
$ID,2$ac.col=98;ac.row=23;$ID,-2$

View file

@ -0,0 +1,247 @@
$FG,5$Using this Library$FG$
$HL,1$#include "MakeCosmicGL"$HL,0$
$FG,2$Simply include MakeCosmicGL.CC located at the root of this repository in your
project. The #include's beneath each title in the documentation are to help
you find where these functions/classes are implemented.
$FG,5$Creating/Freeing Textures and Framebuffers$FG$
$HL,1$#include "Texture"
$HL,0$
$FG,2$CTex2D is used for both textures and framebuffers:$FG$
$HL,1$U0 Tex2DInit(CTex2D *tex, I64 type, I64 w, I64 h);
U0 Tex2DFree(CTex2D *tex);$HL,0$
$FG,2$Where $FG$$FG,9$type$FG$ $FG,2$can be:$FG$
$FG,3$
TEX2D_RAW$FG$ $FG,2$CBGR24 format$FG$
$FG,3$TEX2D_DEPTH$FG$ $FG,2$F64 format$FG$
$FG,3$TEX2D_WAD$FG$ $FG,2$WAD/BMP 8-bit 256-CBGR24 palette compression$FG$
$FG,2$Textures must be made for the frame and depth buffer, which can later be drawn
to a window after the image is rendered onto them. Textures that you intend to
use as render targets such as framebuffers can not be compressed:$FG$
$HL,1$CTex2D frameBuf, depthBuf;
Tex2DInit(&frameBuf, TEX2D_RAW, 640, 480);
Tex2DInit(&depthBuf, TEX2D_DEPTH, 640, 480);$HL,0$
$FG,5$Loading/Clearing Textures$FG$
$FG,2$Tex2DInit merely allocates space, you can then clear the textures with the
following:$FG$
$HL,1$U0 Tex2DColorFill(CTex2D *tex, CBGR24 color);
U0 Tex2DDepthReset(CTex2D *tex);
U0 Tex2DLoadWAD(CTex2D *tex, CWAD *wad, U8 *texName);
$HL,0$
$FG,5$Sampling Textures$FG$
$FG,2$To sample a texture location (such as when texture mapping in a fragment
shader), the following are available:$FG$
$HL,1$U0 Tex2DSampleNorm(CBGR24 *col, CTex2D *tex, F64 u, F64 v);$HL,0$ $FG,2$Samples with normalized 0.0-1.0 uv coordinates.$FG$
$HL,1$U0 Tex2DSampleCoord(CBGR24 *col, CTex2D *tex, I64 u, I64 v);$HL,0$ $FG,2$Samples with raw pixel uv coordinates.$FG$
$FG,5$Displaying Textures$FG$
$FG,2$All texture types can be rendered to the OS framebuffer. Textures and
non-color data (depth) are rendered in grayscale.$FG$
$HL,1$U0 Tex2DDebugDisp(CTex2D *tex, I64 x, I64 y);$HL,0$ $FG,2$Copies directly to OS display buffer rather than window, will be replaced.$FG$
$FG,5$Loading Textures From Common Formats$FG$
$HL,1$#include "TextureImport"
$HL,0$
$FG,5$WAD Textures$FG$
$FG,2$WAD files were a common method of storing textures in early game engines,
popularized by the DOOM/Quake/GldSrc engines. Textures are compressed with
8-bit color pointing to a 256 24-bit color palette. See the WAD section to
learn how to load the CWAD object to pass to this function.
$FG,2$Example WAD loading:$FG$
$HL,1$
CWAD wad;
CTex2D tex;
WADLoad(&wad, "Assets/Textures/HALFLIFE.WAD");
Tex2DLoadWAD(&tex, &wad, "!waterblue");$HL,1$$HL,0$ $FG,2$The loader will initialize the texture.$FG$
WADFree(&wad);
$HL,0$
$FG,5$BMP Images$FG$
$FG,2$BMP images are an extremely simple format to read. You can load 24-bit uncompressed
BMPs like so:$FG$
$HL,1$CTex2D tex;
Tex2DLoadBMP(&tex, "SaintTerry.bmp");$HL,0$ $FG,2$The loader will initialize the texture.$FG$
$FG,5$Loading and Reading WAD Files$FG$
$HL,1$#include "WAD/WADTypes"
#include "WAD/WAD"$HL,0$
$FG,2$WAD files are a general purpose format for storing a flat hierarchy of
directories called "lumps." They were first used by the DOOM engine to hold
game assets, however they have been used by subsequent engines such as Quake
and GldSrc to hold textures. The general purpose WAD manipulation functions
below can be used to access all WAD formats, although some functionality from
other functions may be limited to specific WAD types.$FG$
$HL,1$
U0 WADLoad(CWAD *wad, U8 *fname);
U0 WADFree(CWAD *wad);
$HL,0$
$FG,2$WAD types:$FG$$FG,3$
WAD_TYPE_HL
WAD_TYPE_DOOM
$FG$
$FG,5$Lumps$FG$
$FG,2$These are named directories with no hierarchy. The format for lumps is slightly
different for DOOM and Quake/Half-Life WADs, so a CWADFileLump union is available
to pass general purpose lump pointers.
Lump classes:$FG$
$HL,1$class CWADFileLumpDoom;
class CWADFileLumpHL;
class CWADFileLump;$HL,0$
$FG,2$CWADFileLump can be "interpreted" as either with:$FG$
CWADFileLump.doom
CWADFileLump.hl
$FG,2$CWAD has an internal hash file for fast lump reading. To find a lump by name, use:$FG$
$HL,1$I64 WADFindLump(CWAD *wad, U8 *name, CWADFileLump **lump=NULL);$HL,0$
$FG,2$It returns the lump index, or -1 if not found. **lump can be optionally used to get
the handle to the target lump.$FG$
$FG,5$Shaders$FG$
$HL,1$#include "Shader"
$HL,0$
$FG,2$Shaders are functions that calculate the vertex positions of each triangle in
NDC (normalized device coordinates), and then calculate the color of each
individual fragment (pixel) within the triangles. You can use any model format
you like, as you get to decide what vertex coordinates are returned for each
triangle. $FG$
$FG,5$Uniforms$FG$
$FG,2$Uniforms are unchanging values that will be used by the shader for every
triangle in the model. These are often values like transformation matrices,
texture pointers, or any other material parameters you need. You can provide a
pointer to your uniforms to use in the shader.$FG$
$FG,5$Vertex to Fragment Vertex Attributes$FG$
$FG,2$The vertex shader returns not only the coordinates of the vertices for each
triangle, but also other attributes such as UV coordinates, normals, colors,
etc. Every time the fragment shader is called, the interpolated attributes
for that frag (pixel) are given to the shader.)
$FG,2$You can choose the structure of the F64 array of attributes to be interpolated
by setting the nVertValues and *vertValues from CShader:$FG$
$HL,1$
CShader shd;
shd.nVertValues = 2; $FG,2$In this example, the vertex shader will pass two attributes.$FG$
shd.vertValues = MAlloc(2 * sizeof(I64));
shd.vertValues[0] = SHD_CVEC2; $FG,2$For passing UV coordinate to fragment shader.$FG$
shd.vertValues[1] = SHD_CVEC3;$HL,0$ $FG,2$For passing normal to fragment shader.$FG$
$FG,2$Where the vertValues can be of type:$FG$
$FG,3$
SHD_F64
SHD_CVEC2
SHD_CVEC3
SHD_CVEC4
SHD_CMat4
$FG$
$FG,5$Vertex Shader$FG$
$FG,2$The purpose of the vertex shader is to calculate each triangle's vertex
coordinates in NDC (noramalized device coordinates). The renderer will "plot"
or rasterize these coordinates to the specified render target texture.
Fragments outside of the -1:1 range will not be rendered (as they are
off-texture). $FG$
$SP,"NDC Coordinates:",BI=1$
$HL,1$U0 (*VertShd)(CTri *tri, F64 *vertOutBuf,, U8 *mdlPtr, U8 *uniforms, I64 iTri, i64 nTris);$HL,0$
$FG,3$*tri$FG$ $FG,2$OUTPUT: Final triangle coordinates in NDC$FG$
$FG,3$*mdlPtr$FG$ $FG,2$INPUT: Pointer to model data.$FG$
$FG,3$*vertOutBuf$FG$ $FG,2$OUTPUT: Array of attributes to be interpolated for the frag shader. In order of: [V0 Attr, V1 Attr, V2 Attr] $FG$
$FG,3$*uniforms$FG$ $FG,2$INPUT: Pointer to uniforms.$FG$
$FG,3$iTri$FG$ $FG,2$INPUT: Current triangle.$FG$
$FG,3$nTris$FG$ $FG,2$INPUT: Total number of triangles in model.$FG$
$FG,2$Example of creating and attaching a vertex shader to a CShader:$FG$
$HL,1$CShader shd;
U0 vShader(CTri *tri, F64 *vertOutBuf, U8 *mdlPtr, U8 *uniforms, I64 iTri, I64 nTris)
{
// Set *tri with the iTri from mdlPtr.
}
shd.VertShd = &vShader;$HL,0$
$FG,5$Fragment Shader$FG$
$FG,2$The fragment shader returns the CBGR24 color for a particular fragment (pixel).
It takes uniforms as well as interpolated values from the vertex shader to
calculate each frag's color.
For example, each vertex of a triangle may have a UV coordinate pointing to the
part of the texture it maps to. The three UV coordinate attributes from the
vertex shader will be interpolated into one UV coordinate sent to the fragment
shader. The fragment shader can then sample that pixel color from the texture
included in the uniforms and return that color. Fragment shaders can be used
for all sorts of purposes, including rendering lighting, shadows, warping,
color filtering, etc.$FG$
$HL,1$U0 (*FragShd)(CBGR24 *color, F64 *fragInBuf, U8 *uniforms);$HL,0$
$FG,2$Fragment shaders can be created and attached in the same way as vertex shaders:$FG$
$HL,1$CShader shd;
U0 fShader(CBGR24 *color, F64 *fragInBuf, U8 *uniforms)
{
// Set *color using interpolated F64's from fragInBuf and uniforms
}
shd.FragShd = &fShader;$HL,0$
$FG,5$Rendering$FG$
$HL,1$#include "Math"
#include "Rasterize"
$HL,0$
$FG,2$After models, textures, and shaders are initialized, you can render with these
functions. Currently only triangles can be rendered, however support for all
sprite primitives will be added for performance and ease of use (saves the
steps of rendering textured triangles to draw 2D primitives like in GPU
libraries).$FG$
$HL,1$
U0 RenderTris(CShader *shd, CTex2D *frameBuf, CTex2D *depthBuf, U8 *mdl, U8 *uniforms, I64 nTris);
$HL,0$
õ
¢ÿÿÿ4·ÿÿÿ#ÿ
”ÿÿÿÔÿÿÿ
”ÿÿÿWÔÿÿÿW
”ÿÿÿ”ÿÿÿW
ÔÿÿÿÔÿÿÿW´ÿÿÿ7´ÿÿÿ´ÿÿÿ7Óÿÿÿ7´ÿÿÿ7Ëÿÿÿ ¡ÿÿÿY: +1Ùÿÿÿ4X: +1ÐÿÿÿZ: +1­ÿÿÿ[-1„ÿÿÿ4-1šÿÿÿJ-1 ANDC maps to texture
coordinates when
rasterizing.
8£8
·¸P
¸P P
P 
¸  
œÿÿÿ*§ÿÿÿB
§ÿÿÿBÁÿÿÿ>
Áÿÿÿ>œÿÿÿ*
Ä+ú=
ú=ÎC
ÎCÄ+

View file

@ -0,0 +1,233 @@
/**
@defgroup Draw Draw
@brief Functions for drawing to textures.
*/
/**
@ingroup Draw
@brief Draw pixel on color texture. Does not check boundaries, point
must be fully inside texture.
@param[in,out] tex Color texture to draw to.
@param[in] x X position.
@param[in] y Y position.
@param[in] color Color of point.
*/
U0 DrawPixel(CTex2D *tex, I64 x, I64 y, CBGR24 color)
{
tex->rawBuf[x + y * tex->w] = color;
}
/**
@ingroup Draw
@brief Draw line on color texture. Does not check boundaries, line must
be fully inside texture.
@param[in,out] tex Color texture to draw to.
@param[in] x0 Start x.
@param[in] y0 Start y.
@param[in] x1 End x.
@param[in] y1 End y.
@param[in] color Color of line.
*/
U0 DrawLine(CTex2D *tex, I64 x0, I64 y0, I64 x1, I64 y1, CBGR24 color)
{
Bool steep = (Abs(y1 - y0) > Abs(x1 - x0));
I64 temp;
if (steep == TRUE)
{
temp = x0;
x0 = y0;
y0 = temp;
temp = x1;
x1 = y1;
y1 = temp;
}
if (x0 > x1)
{
temp = x0;
x0 = x1;
x1 = temp;
temp = y0;
y0 = y1;
y1 = temp;
}
I64 delta_x = x1 - x0;
I64 delta_y = Abs(y1 - y0);
I64 error = delta_x / 2;
I64 step_y;
if (y0 < y1)
{
step_y = 1;
}
else
{
step_y = -1;
}
I64 y = y0;
I64 x;
for (x = x0; x < (x1 + 1); x++)
{
if (steep == TRUE)
{
tex->rawBuf[y + x * tex->w] = color;
}
else
{
tex->rawBuf[x + y * tex->w] = color;
}
error -= delta_y;
if (error < 0)
{
y += step_y;
error += delta_x;
}
}
}
/**
@ingroup Draw
@brief Draw single color triangle to color texture. Does not check
boundaries, triangle must be fully inside texture.
@param[in,out] tex Color texture to draw to.
@param[in] x0 First vertex x.
@param[in] y0 First vertex y.
@param[in] x1 Second vertex x.
@param[in] y1 Second vertex y.
@param[in] x2 Third vertex x.
@param[in] y2 Third vertex y.
@param[in] color Color of triangle.
*/
U0 DrawTriangle(CTex2D *tex, I64 x0, I64 y0, I64 x1, I64 y1, I64 x2, I64 y2,
CBGR24 color)
{
I64 temp;
F64 ftemp;
if (y0 > y1)
{
temp = x0;
x0 = x1;
x1 = temp;
temp = y0;
y0 = y1;
y1 = temp;
}
if (y0 > y2)
{
temp = x0;
x0 = x2;
x2 = temp;
temp = y0;
y0 = y2;
y2 = temp;
}
if (y1 > y2)
{
temp = x1;
x1 = x2;
x2 = temp;
temp = y1;
y1 = y2;
y2 = temp;
}
Bool middle_line_drawn = FALSE;
F64 x_delta;
F64 y_delta;
F64 left_delta;
F64 right_delta;
F64 left_x;
F64 right_x;
I64 y, lX, rX;
I64 left_index, right_index;
I64 width;
// Bottom Half
if (y0 != y1)
{
x_delta = (x1 - x0);
y_delta = (y1 - y0);
left_delta = x_delta / y_delta;
x_delta = (x2 - x0);
y_delta = (y2 - y0);
right_delta = x_delta / y_delta;
if (left_delta > right_delta)
{
ftemp = left_delta;
left_delta = right_delta;
right_delta = ftemp;
}
left_x = x0;
right_x = x0;
middle_line_drawn = TRUE;
for (y = y0; y < (y1 + 1); y++)
{
lX = left_x + 0.5;
rX = right_x + 0.5;
left_index = y * tex->w + lX;
right_index = y * tex->w + rX;
width = right_index - left_index;
MemSetU32(tex->rawBuf + left_index, color, width);
left_x += left_delta;
right_x += right_delta;
}
}
// Top Half
if (y1 != y2)
{
x_delta = -(x1 - x2);
y_delta = (y1 - y2);
left_delta = x_delta / y_delta;
x_delta = -(x0 - x2);
y_delta = (y0 - y2);
right_delta = x_delta / y_delta;
if (left_delta > right_delta)
{
ftemp = left_delta;
left_delta = right_delta;
right_delta = ftemp;
}
left_x = x2;
right_x = x2;
if (middle_line_drawn == TRUE)
{
y1 += 1;
}
for (y = y2; y > (y1 - 1); y--)
{
lX = left_x + 0.5;
rX = right_x + 0.5;
left_index = y * tex->w + lX;
right_index = y * tex->w + rX;
width = right_index - left_index;
MemSetU32(tex->rawBuf + left_index, color, width);
left_x += left_delta;
right_x += right_delta;
}
}
}

View file

@ -0,0 +1,165 @@
/**
@ingroup Draw
@brief Draw single color rectangle.
@param[in,out] tex Texture to draw to.
@param[in] x0 Start corner x.
@param[in] y0 Start corner y.
@param[in] x1 End corner x.
@param[in] y1 End corner y.
@param[in] color Color of rectangle.
*/
U0 DrawRectFill(CTex2D *tex, I64 x0, I64 y0, I64 x1, I64 y1, CBGR24 color)
{
I64 xMaxIndex = tex->w - 1;
I64 yMaxIndex = tex->h - 1;
I64 xMin = Clamp(Min(x0, x1), 0, xMaxIndex);
I64 xMax = Clamp(Max(x0, x1), 0, xMaxIndex);
I64 yMin = Clamp(Min(y0, y1), 0, yMaxIndex);
I64 yMax = Clamp(Max(y0, y1), 0, yMaxIndex);
I64 xLen = xMax - xMin;
I64 y;
for (y = yMin; y < yMax; y++)
{
MemSetU32(&tex->rawBuf[xMin + y * tex->w], color, xLen);
}
}
/**
@ingroup Draw
@brief Draw 1px soft rectangle outline (corners not filled).
@param[in,out] tex Texture to draw to.
@param[in] x0 Start corner x.
@param[in] y0 Start corner y.
@param[in] x1 End corner x.
@param[in] y1 End corner y.
@param[in] color Color of rectangle.
@param[in] shadeColor (Optional) color of bottom right corner
for shading effect.
*/
U0 DrawRectSoftOutline(CTex2D *tex, I64 x0, I64 y0, I64 x1, I64 y1,
CBGR24 color, CBGR24 shadeColor = 0x7FFFFFFF)
{
if (shadeColor == 0x7FFFFFFF)
shadeColor = color;
I64 xMaxIndex = tex->w - 1;
I64 yMaxIndex = tex->w - 1;
I64 xMin = Clamp(Min(x0, x1), 0, xMaxIndex);
I64 xMax = Clamp(Max(x0, x1), 0, xMaxIndex);
I64 yMin = Clamp(Min(y0, y1), 0, yMaxIndex);
I64 yMax = Clamp(Max(y0, y1), 0, yMaxIndex);
I64 xLen = xMax - xMin - 1;
// Top border
MemSetU32(&tex->rawBuf[xMin + 1 + yMin * tex->w], color, xLen);
// Bottom border
MemSetU32(&tex->rawBuf[xMin + 1 + yMax * tex->w], shadeColor, xLen);
// Left/Right border
I64 y;
for (y = yMin + 1; y < yMax; y++)
{
tex->rawBuf[xMin + y * tex->w] = color;
tex->rawBuf[xMax + y * tex->w] = shadeColor;
}
}
/**
@ingroup Draw
@brief Draw 1px rectangle outline.
@param[in,out] tex Texture to draw to.
@param[in] x0 Start corner x.
@param[in] y0 Start corner y.
@param[in] x1 End corner x.
@param[in] y1 End corner y.
@param[in] color Color of rectangle.
@param[in] shadeColor (Optional) color of bottom right corner
for shading effect.
*/
U0 DrawRectOutline(CTex2D *tex, I64 x0, I64 y0, I64 x1, I64 y1,
CBGR24 color, CBGR24 shadeColor = 0x7FFFFFFF)
{
if (shadeColor == 0x7FFFFFFF)
shadeColor = color;
I64 xMaxIndex = tex->w - 1;
I64 yMaxIndex = tex->w - 1;
I64 xMin = Clamp(Min(x0, x1), 0, xMaxIndex);
I64 xMax = Clamp(Max(x0, x1), 0, xMaxIndex);
I64 yMin = Clamp(Min(y0, y1), 0, yMaxIndex);
I64 yMax = Clamp(Max(y0, y1), 0, yMaxIndex);
I64 xLen = xMax - xMin + 1;
// Top border
MemSetU32(&tex->rawBuf[xMin + yMin * tex->w], color, xLen);
// Bottom border
MemSetU32(&tex->rawBuf[xMin + yMax * tex->w], shadeColor, xLen);
// Left/Right border
I64 y;
for (y = yMin + 1; y < yMax; y++)
{
tex->rawBuf[xMin + y * tex->w] = color;
tex->rawBuf[xMax + y * tex->w] = shadeColor;
}
}
/**
@ingroup Draw
@brief Draw two color vertical gradient rectangle.
@param[in,out] tex Texture to draw to.
@param[in] x0 Start corner x.
@param[in] y0 Start corner y.
@param[in] x1 End corner x.
@param[in] y1 End corner y.
@param[in] colorTop Top color of gradient.
@param[in] colorBottom Bottom color of gradient.
@param[in] shadeColor (Optional) color of bottom right corner
for shading effect.
@param[in] tStart (Optional) start of gradient.
@param[in] tEnd (Optional) end of gradient.
*/
U0 DrawRectVertGradient(CTex2D *tex, I64 x0, I64 y0, I64 x1, I64 y1,
CBGR24 colorTop, CBGR24 colorBottom, F64 tStart = 0.0, F64 tEnd = 1.0)
{
I64 xMaxIndex = tex->w - 1;
I64 yMaxIndex = tex->h - 1;
I64 xMin = Clamp(Min(x0, x1), 0, xMaxIndex);
I64 xMax = Clamp(Max(x0, x1), 0, xMaxIndex);
I64 yMinReal = Min(y0, y1);
I64 yMin = Clamp(yMinReal, 0, yMaxIndex);
I64 yMaxReal = Max(y0, y1);
I64 yMax = Clamp(yMaxReal, 0, yMaxIndex);
I64 xLen = xMax - xMin;
F64 yHeight = yMaxReal - yMinReal + 1;
F64 t;
F64 rDiff = colorBottom.r - colorTop.r;
F64 gDiff = colorBottom.g - colorTop.g;
F64 bDiff = colorBottom.b - colorTop.b;
F64 r, g, b;
I64 y;
CBGR24 color;
for (y = yMin; y < yMax; y++)
{
t = Clamp((y - yMinReal) / yHeight, tStart, tEnd);
r = t * rDiff;
g = t * gDiff;
b = t * bDiff;
color.r = colorTop.r + r;
color.g = colorTop.g + g;
color.b = colorTop.b + b;
MemSetU32(&tex->rawBuf[xMin + y * tex->w], color, xLen);
}
}

View file

@ -0,0 +1,86 @@
/**
@ingroup Draw
@brief Draw a single color character to color texture.
@param[in,out] tex Texture to draw to.
@param[in] x X position to draw character at.
@param[in] y Y position to draw character at.
*/
U0 DrawChar(CTex2D *tex, I64 x, I64 y, U8 char, CBGR24 color,
U64 *font = text.font)
{
// Check if off-screen
if (x >= tex->w || x <= -FONT_WIDTH)
return;
I64 i, j;
for (j = 0; j < FONT_HEIGHT; j++)
{
for (i = 0; i < FONT_WIDTH; i++)
{
if (font[char].u8[j] & (1 << i))
tex->rawBuf[x + i + (y + j) * tex->w] = color;
}
}
}
/**
@ingroup Draw
@brief Draw a single color string to color texture.
@param[in,out] tex Texture to draw to.
@param[in] x X position to draw text at.
@param[in] y Y position to draw text at.
@param[in] color Color of text.
@param[in] font Pointer to font buffer. System font by default.
*/
U0 DrawString(CTex2D *tex, I64 x, I64 y, U8 *str, CBGR24 color,
U64 *font = text.font)
{
I64 cur = 0; // String cursor
I64 xCur = x; // Screen cursors
I64 yCur = y;
U8 char = 0; // Character to draw
while (str[cur] != NULL)
{
switch (str[cur])
{
// Escape sequence
case '\\':
"ESCAPE SEQ\n";
switch (str[cur + 1])
{
case 'n':
xCur = x;
yCur += FONT_HEIGHT;
"NEWLINE\n";
break;
// Not a real tab, but what mong uses tabs in labels?
case 't':
xCur += FONT_WIDTH * 4;
break;
case '\\':
DrawChar(tex, xCur, yCur, '\\', color, font);
xCur += FONT_WIDTH;
break;
}
cur += 2;
break;
case ' ':
cur++;
xCur += FONT_WIDTH;
break;
default:
DrawChar(tex, xCur, yCur, str[cur], color, font);
cur++;
xCur += FONT_WIDTH;
break;
}
}
}

View file

@ -0,0 +1,47 @@
/**
@ingroup Draw
@brief Draw non-transformed color texture with blit operation.
Does not yet check if texture being drawn is entirely inside the texture
being drawn to.
@param[in,out] dst Destination texture to draw to.
@param[in] src Source texture to draw.
@param[in] x X location to draw texture.
@param[in] y Y location to draw texture.
@param[in] transparent (optional) use alpha as mask. False by default.
*/
U0 DrawTexture(CTex2D *dst, CTex2D *src, I64 x, I64 y,
Bool transparent = FALSE)
{
I64 xC, yC; // Current width/height position being copied from
I64 srcW = src->w; // Don't think the compiler is optimizing this so I am
I64 srcH = src->h;
I64 dstW = dst->w;
if (transparent)
{
for (yC = 0; yC < srcH; yC++)
{
for (xC = 0; xC < srcW; xC++)
{
if (src->rawBuf[xC + yC * srcW].pad == 255)
{
// Assume target doesn't care about alpha byte being copied
dst->rawBuf[(x + xC) + (y + yC) * dstW] =
src->rawBuf[xC + yC * srcW];
}
}
}
}
else
{
for (yC = 0; yC < srcH; yC++)
{
MemCopy(&dst->rawBuf[x + (y + yC) * dstW],
&src->rawBuf[yC * srcW], sizeof(CBGR24) * srcW);
}
}
}

View file

@ -0,0 +1,25 @@
/* Draws text button, returns col/row for next button in nCol/nRow. */
U0 DrawTextButton(CTex2D *tex, I64 col, I64 row, U8 *str, I64 size = 0,
I64 *nCol = NULL, I64 *nRow = NULL)
{
if (size == 0)
size = StrLen(str);
I64 x = col * FONT_WIDTH;
I64 y = row * FONT_HEIGHT;
DrawRectSoftOutline(tex, x - 3, y - 3, x + 1 + size * FONT_WIDTH,
y + FONT_HEIGHT + 1, gr_palette[DKGRAY]);
DrawRectVertGradient(tex, x - 2, y - 2, x + 1 + size * FONT_WIDTH,
y + FONT_HEIGHT + 1, gr_palette[DKGRAY], gr_palette[WHITE]);
DrawString(tex, x, y, str, gr_palette[BLACK ]);
if (nCol != NULL)
*nCol += size + 1;
if (nRow != NULL)
*nRow += 2;
}

View file

@ -0,0 +1,42 @@
// Color palette indexing
#define C_BCKGND 0
#define C_BCKGNDLIGHT 1 // Light for highlights
#define C_BCKGNDSHD 2 // Shade for shadows
#define C_TEXT 3
CBGR24 palette[4] =
{
0x282828, // C_BCKGND
0x383838, // C_BCKGNDLIGHT
0x101010, // C_BCKGNDSHD
0xFFFFFF // C_TEXT
};
/* Draws text button, returns col/row for next button in nCol/nRow. */
U0 DrawTextButton(CTex2D *tex, I64 col, I64 row, U8 *str, I64 size = 0,
I64 *nCol = NULL, I64 *nRow = NULL)
{
if (size == 0)
size = StrLen(str);
I64 x = col * FONT_WIDTH;
I64 y = row * FONT_HEIGHT;
CBGR24 blue = 0x0000FF;
DrawRectSoftOutline(tex, x - 3, y - 3, x + 1 + size * FONT_WIDTH,
y + FONT_HEIGHT + 1, palette[C_BCKGNDLIGHT]);
DrawRectVertGradient(tex, x - 2, y - 2, x + 1 + size * FONT_WIDTH,
y + FONT_HEIGHT + 1, palette[C_BCKGNDLIGHT], palette[C_BCKGND]);
DrawString(tex, x, y, str, palette[C_TEXT]);
if (nCol != NULL)
*nCol += size + 1;
if (nRow != NULL)
*nRow += 2;
}

View file

@ -0,0 +1,17 @@
/* Include this file to rebuild the CosmicGL library. */
Cd(__DIR__);;
#include "Math/Math"
#include "Texture/Texture"
#include "Draw/Primitive"
#include "Draw/Texture"
#include "Draw/Rectangle"
#include "Draw/Text"
#include "Draw/UISmooth"
#include "Render/Shader"
#include "Render/Rasterize"
#include "WAD/WADTypes"
#include "WAD/WAD"
#include "Texture/TextureImport"
#include "WAD/DoomTypes"
#include "WAD/DoomMap"

View file

@ -0,0 +1,382 @@
/* Legacy math library. Is being replaced\, however it will remain
until Rasterize.CC is ported over to the new math library. */
class CVec4
{
F64 x;
F64 y;
F64 z;
F64 w;
};
class CVec3
{
F64 x;
F64 y;
F64 z;
};
class CVec2
{
F64 x;
F64 y;
};
class CIVec2
{
I64 x;
I64 y;
};
class CTri
{
CVec3 p[3];
};
class CMat4
{
F64 e[4][4];
};
CVec3 *Add3(CVec3 *a, CVec3 *b)
{
CVec3 *c = MAlloc(sizeof(CVec3));
c->x = a->x + b->x;
c->y = a->y + b->y;
c->z = a->z + b->z;
return c;
}
CVec2 *Add2(CVec2 *a, CVec2 *b)
{
CVec2 *c = MAlloc(sizeof(CVec2));
c->x = a->x + b->x;
c->y = a->y + b->y;
return c;
}
CVec3 *Sub3(CVec3 *a, CVec3 *b)
{
CVec3 *c = MAlloc(sizeof(CVec3));
c->x = a->x - b->x;
c->y = a->y - b->y;
c->z = a->z - b->z;
return c;
}
CVec2 *Sub2(CVec2 *a, CVec2 *b)
{
CVec2 *c = MAlloc(sizeof(CVec2));
c->x = a->x - b->x;
c->y = a->y - b->y;
return c;
}
CVec3 *Div3S(CVec3 *a, F64 b)
{
CVec3 *c = MAlloc(sizeof(CVec3));
c->x = a->x / b;
c->y = a->y / b;
c->z = a->z / b;
return c;
}
CVec2 *Div2S(CVec2 *a, F64 b)
{
CVec2 *c = MAlloc(sizeof(CVec2));
c->x = a->x / b;
c->y = a->y / b;
return c;
}
CVec4 *Mul4S(CVec4 *a, F64 b)
{
CVec4 *c = MAlloc(sizeof(CVec4));
c->x = a->x * b;
c->y = a->y * b;
c->z = a->z * b;
c->w = a->w * b;
return c;
}
CVec3 *Mul3S(CVec3 *a, F64 b)
{
CVec3 *c = MAlloc(sizeof(CVec3));
c->x = a->x * b;
c->y = a->y * b;
c->z = a->z * b;
return c;
}
CVec2 *Mul2S(CVec2 *a, F64 b)
{
CVec2 *c = MAlloc(sizeof(CVec2));
c->x = a->x * b;
c->y = a->y * b;
return c;
}
F64 Dot3(CVec3 *a, CVec3 *b)
{
return (a->x * b->x) + (a->y * b->y) + (a->z * b->z);
}
F64 Dot2(CVec2 *a, CVec2 *b)
{
return (a->x * b->x) + (a->y * b->y);
}
CVec3 *Norm3(CVec3 *a)
{
F64 length = Sqrt(Sqr(a->x) + Sqr(a->y) + Sqr(a->z));
a->x /= length;
a->y /= length;
a->z /= length;
return a;
}
CVec2 *Norm2(CVec2 *a)
{
F64 length = Sqrt(Sqr(a->x) + Sqr(a->y));
a->x /= length;
a->y /= length;
return a;
}
// Create direction Vec4 from Vec3
CVec4 *Vec4Dir(CVec3 *a)
{
CVec4 *b = MAlloc(sizeof(CVec4));
MemCopy(b, a, 24);
b->w = 0;
return b;
}
// Create position Vec4 from Vec3
CVec4 *Vec4Pos(CVec3 *a)
{
CVec4 *b = MAlloc(sizeof(CVec4));
MemCopy(b, a, 24);
b->w = 1;
return b;
}
// Create Vec3 from Vec4
CVec3 *Vec3Pos(CVec4 *a)
{
CVec3 *b = MAlloc(sizeof(CVec3));
MemCopy(b, a, 24);
return b;
}
CVec4 *MulM44(CMat4 *a, CVec4 *b)
{
CVec4 *c = MAlloc(sizeof(CVec4));
c->x = (a->e[0][0] * b->x) + (a->e[0][1] * b->y) + (a->e[0][2] * b->z) + (a->e[0][3] * b->w);
c->y = (a->e[1][0] * b->x) + (a->e[1][1] * b->y) + (a->e[1][2] * b->z) + (a->e[1][3] * b->w);
c->z = (a->e[2][0] * b->x) + (a->e[2][1] * b->y) + (a->e[2][2] * b->z) + (a->e[2][3] * b->w);
c->w = (a->e[3][0] * b->x) + (a->e[3][1] * b->y) + (a->e[3][2] * b->z) + (a->e[3][3] * b->w);
return c;
}
CMat4 *MulM4M4(CMat4 *a, CMat4 *b)
{
CMat4 *c = MAlloc(sizeof(CMat4));
c->e[0][0] = (a->e[0][0] * b->e[0][0])+(a->e[0][1] * b->e[1][0])+(a->e[0][2] * b->e[2][0])+(a->e[0][3] * b->e[3][0]);
c->e[0][1] = (a->e[0][0] * b->e[0][1])+(a->e[0][1] * b->e[1][1])+(a->e[0][2] * b->e[2][1])+(a->e[0][3] * b->e[3][1]);
c->e[0][2] = (a->e[0][0] * b->e[0][2])+(a->e[0][1] * b->e[1][2])+(a->e[0][2] * b->e[2][2])+(a->e[0][3] * b->e[3][2]);
c->e[0][3] = (a->e[0][0] * b->e[0][3])+(a->e[0][1] * b->e[1][3])+(a->e[0][2] * b->e[2][3])+(a->e[0][3] * b->e[3][3]);
c->e[1][0] = (a->e[1][0] * b->e[0][0])+(a->e[1][1] * b->e[1][0])+(a->e[1][2] * b->e[2][0])+(a->e[1][3] * b->e[3][0]);
c->e[1][1] = (a->e[1][0] * b->e[0][1])+(a->e[1][1] * b->e[1][1])+(a->e[1][2] * b->e[2][1])+(a->e[1][3] * b->e[3][1]);
c->e[1][2] = (a->e[1][0] * b->e[0][2])+(a->e[1][1] * b->e[1][2])+(a->e[1][2] * b->e[2][2])+(a->e[1][3] * b->e[3][2]);
c->e[1][3] = (a->e[1][0] * b->e[0][3])+(a->e[1][1] * b->e[1][3])+(a->e[1][2] * b->e[2][3])+(a->e[1][3] * b->e[3][3]);
c->e[2][0] = (a->e[2][0] * b->e[0][0])+(a->e[2][1] * b->e[1][0])+(a->e[2][2] * b->e[2][0])+(a->e[2][3] * b->e[3][0]);
c->e[2][1] = (a->e[2][0] * b->e[0][1])+(a->e[2][1] * b->e[1][1])+(a->e[2][2] * b->e[2][1])+(a->e[2][3] * b->e[3][1]);
c->e[2][2] = (a->e[2][0] * b->e[0][2])+(a->e[2][1] * b->e[1][2])+(a->e[2][2] * b->e[2][2])+(a->e[2][3] * b->e[3][2]);
c->e[2][3] = (a->e[2][0] * b->e[0][3])+(a->e[2][1] * b->e[1][3])+(a->e[2][2] * b->e[2][3])+(a->e[2][3] * b->e[3][3]);
c->e[3][0] = (a->e[3][0] * b->e[0][0])+(a->e[3][1] * b->e[1][0])+(a->e[3][2] * b->e[2][0])+(a->e[3][3] * b->e[3][0]);
c->e[3][1] = (a->e[3][0] * b->e[0][1])+(a->e[3][1] * b->e[1][1])+(a->e[3][2] * b->e[2][1])+(a->e[3][3] * b->e[3][1]);
c->e[3][2] = (a->e[3][0] * b->e[0][2])+(a->e[3][1] * b->e[1][2])+(a->e[3][2] * b->e[2][2])+(a->e[3][3] * b->e[3][2]);
c->e[3][3] = (a->e[3][0] * b->e[0][3])+(a->e[3][1] * b->e[1][3])+(a->e[3][2] * b->e[2][3])+(a->e[3][3] * b->e[3][3]);
return c;
}
// Normalized Vec4 to RGBA
U0 Vec4Col(CVec4 *col, CBGR24 *bgrcol)
{
bgrcol->r = (col->x * 255.0);
bgrcol->g = (col->y * 255.0);
bgrcol->b = (col->z * 255.0);
bgrcol->pad = (col->w * 255.0);
}
// Normalized Vec3 to RGBA
U0 Vec3Col(CVec3 *col, CBGR24 *bgrcol)
{
bgrcol->r = (col->x * 255.0);
bgrcol->g = (col->y * 255.0);
bgrcol->b = (col->z * 255.0);
bgrcol->pad = 255.0;
}
U0 Barycentric2(CVec2 *p, CVec2 *a, CVec2 *b, CVec2 *c, F64 *u, F64 *v, F64 *w)
{
CVec2 *v0 = Sub2(b, a);
CVec2 *v1 = Sub2(c, a);
CVec2 *v2 = Sub2(p, a);
F64 d00 = Dot2(v0, v0);
F64 d01 = Dot2(v0, v1);
F64 d11 = Dot2(v1, v1);
F64 d20 = Dot2(v2, v0);
F64 d21 = Dot2(v2, v1);
F64 denom = d00 * d11 - d01 * d01;
*v = (d11 * d20 - d01 * d21)/denom;
*w = (d00 * d21 - d01 * d20)/denom;
*u = 1.0 - *v - *w;
Free(v0);
Free(v1);
Free(v2);
}
CVec2 Ayy,Bee,Cee, P;
Ayy.x = 0;
Ayy.y = 0;
Bee.x = 3;
Bee.y = 0;
Cee.x = 0;
Cee.y = 3;
U0 SetTranslateM4(CMat4 *mat, CVec3 *translation)
{
MemSet(mat, 0, sizeof(CMat4));
mat->e[0][0] = 1;
mat->e[1][1] = 1;
mat->e[2][2] = 1;
mat->e[3][3] = 1;
mat->e[0][3] = translation->x;
mat->e[1][3] = translation->y;
mat->e[2][3] = translation->z;
}
U0 SetScaleM4(CMat4 *mat, CVec3 *scale)
{
MemSet(mat, 0, sizeof(CMat4));
mat->e[0][0] = scale->x;
mat->e[1][1] = scale->y;
mat->e[2][2] = scale->z;
mat->e[3][3] = 1;
}
U0 SetRotXM4(CMat4 *mat, F64 rot)
{
MemSet(mat, 0, sizeof(CMat4));
mat->e[0][0] = 1;
mat->e[3][3] = 1;
F64 x = Cos(rot);
F64 y = Sin(rot);
mat->e[1][1] = x;
mat->e[1][2] = -y;
mat->e[2][1] = y;
mat->e[2][2] = x;
}
U0 SetRotYM4(CMat4 *mat, F64 rot)
{
MemSet(mat, 0, sizeof(CMat4));
mat->e[1][1] = 1;
mat->e[3][3] = 1;
F64 x = Cos(rot);
F64 y = Sin(rot);
mat->e[0][0] = x;
mat->e[0][2] = y;
mat->e[2][0] = -y;
mat->e[2][2] = x;
}
U0 SetRotZM4(CMat4 *mat, F64 rot)
{
MemSet(mat, 0, sizeof(CMat4));
mat->e[2][2] = 1;
mat->e[3][3] = 1;
F64 x = Cos(rot);
F64 y = Sin(rot);
mat->e[0][0] = x;
mat->e[0][1] = -y;
mat->e[1][0] = y;
mat->e[1][1] = x;
}
U0 TranslateM4(CMat4 *mat, CVec3 *translation)
{
// Generate CMat4 translation matrix
CMat4 *translateMat = MAlloc(sizeof(CMat4));
SetTranslateM4(translateMat, translation);
CMat4 *finalMat = MulM4M4(mat, translateMat);
MemCopy(mat, finalMat, sizeof(CMat4));
Free(finalMat);
Free(translateMat);
}
U0 F32toF64(U32 *float, U64 *double)
{
MemCopy(&double->u32[1], float, 4);
// Isolate parts of F32
U64 MASK_SIGN = 0b1000000000000000000000000000000000000000000000000000000000000000;
U64 MASK_EXP = 0b0111111110000000000000000000000000000000000000000000000000000000;
U64 MASK_MANT = 0b0000000001111111111111111111111100000000000000000000000000000000;
U64 EXP = *double & MASK_EXP;
U64 MANT = *double & MASK_MANT;
// Clear original F64 so that the masked values can be OR'd in
*double = *double & MASK_SIGN;
// Exponent of F64 is 11 bits instead of 8, shift mantissa by 3 and OR it back in
MANT = MANT >> 3;
*double = *double | MANT;
// Shift exponent to regular int format
// F32: [1 bit sign][8 bit exponent][23 bit mantissa]
EXP = EXP >> 55; // 23 + 32 to get it in regular int format
if (EXP != 0)
{
EXP += 896; // -127, +1023
EXP = EXP << 52;
}
*double = *double | EXP;
}

View file

@ -0,0 +1,29 @@
class CVec2
{
F64 x, y;
};
class CIVec2
{
I64 x, y;
};
class CVec3
{
F64 x, y, z;
};
class CIVec3
{
I64 x, y, z;
};
class CVec4
{
F64 x, y, z, w;
};
class CIVec4
{
I64 x, y, z, w;
};

View file

@ -0,0 +1,318 @@
/* Initialize CVec2 from F64 pointer. */
U0 Vec2(F64 *a, CVec2 *o)
{
o->x = a[0];
o->y = a[1];
}
/* Copy CVec2 into CVec2. */
U0 Copy2(CVec2 *a, CVec2 *o)
{
o->x = a->x;
o->y = a->y;
}
/* Fill CVec2 with F64 */
U0 Fill2S(CVec2 *v, F64 val)
{
v->x = v->y = val;
}
/* Fill CIVec2 with I64 */
U0 FillI2S(CIVec2 *v, I64 val)
{
v->x = v->y = val;
}
/* Clear CVec2 with zeros. */
U0 Zero2(CVec2 *v)
{
v->x = v->y = 0.0;
}
/* Clear CVec2 with ones. */
U0 One2(CVec2 *v)
{
v->x = v->y = 1.0;
}
/* Dot product of two CVec2. */
U0 Dot2(CVec2 *a, CVec2 *b, F64 *o)
{
*o = (a->x * b->x) + (a->y * b->y);
}
/* Z component of cross product of two CVec2. */
U0 Cross2(CVec2 *a, CVec2 *b, F64 *o)
{
*o = (a->x * b->y) - (a->y * b->x);
}
/* Norm^2 (magnitude^2) of CVec2. */
U0 NormSqr2(CVec2 *a, F64 *o)
{
*o = Sqr(a->x) + Sqr(a->y);
}
/* Norm (magnitude) of CVec2. */
U0 Norm2(CVec2 *a, F64 *o)
{
*o = Sqrt(Sqr(v->x) + Sqr(v->y));
}
/* Add CVec2 to CVec2. */
U0 Add2(CVec2 *a, CVec2 *b, CVec2 *o)
{
o->x = a->x + b->x;
o->y = a->y + b->y;
}
/* Add CVec2 to F64. */
U0 Add2S(CVec2 *a, F64 b, CVec2 *o)
{
o->x = a->x + b;
o->y = a->y + b;
}
/* Sub CVec2 from CVec2. */
U0 Sub2(CVec2 *a, CVec2 *b, CVec2 *o)
{
o->x = a->x - b->x;
o->y = a->y - b->y;
}
/* Sub CVec2 from F64. */
U0 Sub2S(CVec2 *a, F64 b, CVec2 *o)
{
o->x = a->x - b;
o->y = a->y - b;
}
/* Multiply CVec2 with CVec2. */
U0 Mul2(CVec2 *a, CVec2 *b, CVec2 *o)
{
o->x = a->x * b->x;
o->y = a->y * b->y;
}
/* Scale CVec2 by F64. */
U0 Scale2S(CVec2 *a, F64 b, CVec2 *o)
{
o->x = a->x * b;
o->y = a->y * b;
}
/* Scale CVec2 unit vector by F64. */
U0 ScaleUnit2(CVec2 *a, F64 b, CVec2 *o)
{
// Norm2(a, &norm)
F64 norm = Sqrt(Sqr(a->x) + Sqr(a->y));
if (norm == 0.0)
{
// Zero2(a)
a->x = a->y = 0.0;
return;
}
// Scale2(a, b / norm, o);
F64 scale = b / norm;
o->x = a->x * scale;
o->y = a->y * scale;
}
/* Divide CVec2 by CVec2. */
U0 Div2(CVec2 *a, CVec2 *b, CVec2 *o)
{
o->x = a->x / b->x;
o->y = b->y / b->y;
}
/* Divide CVec2 by F64. */
U0 Div2S(CVec2 *a, F64 b, CVec2 *o)
{
o->x = a->x / b;
o->y = a->y / b;
}
/* Square root of CVec2 components. */
U0 Sqrt2(CVec2 *a, CVec2 *o)
{
o->x = Sqrt(a->x);
o->y = Sqrt(a->y);
}
/* Sign of components as -1, 0, or 1. */
U0 Sign2(CVec2 *a, CVec2 *o)
{
o->x = ((o->x > 0.0) - (val < 0.0));
o->y = ((o->y > 0.0) - (val < 0.0));
}
/* Add CVec2 to CVec2 to output CVec2. */
U0 AddAdd2(CVec2 *a, CVec2 *b, CVec2 *o)
{
o->x += a->x + b->x;
o->y += a->y + b->y;
}
/* Subtract CVec2 from CVec2, add to output CVec2. */
U0 SubAdd2(CVec2 *a, CVec2 *b, CVec2 *o)
{
o->x += a->x - b->x;
o->y += a->y - b->y;
}
/* Multiply CVec2 by CVec2, add to output CVec2. */
U0 MulAdd2(CVec2 *a, CVec2 *b, CVec2 *o)
{
o->x += a->x * b->x;
o->y += a->y * b->y;
}
/* Multiply CVec2 by F64, add to output CVec2. */
U0 MulAdd2S(CVec2 *a, F64 b, CVec2 *o)
{
o->x += a->x * b;
o->y += a->y * b;
}
/* Add maximum of each CVec2 component to output CVec2. */
U0 MaxAdd2(CVec2 *a, CVec2 *b, CVec2 *o)
{
o->x += Max(a->x, b->x);
o->y += Max(a->y, b->y);
}
/* Add minimum of each CVec2 component to output CVec2. */
U0 MinAdd2(CVec2 *a, CVec2 *b, CVec2 *o)
{
o->x += Min(a->x, b->x);
o->y += Min(a->y, b->y);
}
/* Negate vector components (*-1) to output CVec2. */
U0 NegateTo2(CVec2 *a, CVec2 *o)
{
o->x = -a->x;
o->y = -a->y;
}
/* Negate vector components (*-1). */
U0 Negate2(CVec2 *v)
{
v->x = -v->x;
v->y = -v->y;
}
/* Normalize CVec2 to output CVec2. */
U0 NormalizeTo2(CVec2 *a, CVec2 *o)
{
// Norm2(a, &norm)
F64 norm = Sqrt(Sqr(a->x) + Sqr(a->y));
if (norm == 0.0)
{
// Zero2(o)
o->x = o->y = 0.0;
return;
}
// Scale2(a, 1.0 / norm, o)
F64 scale = 1.0 / norm;
o->x = a->x * scale;
o->y = a->y * scale;
}
/* Normalize CVec2. */
U0 Normalize2(CVec2 *v)
{
// Norm2(v, &norm)
F64 norm = Sqrt(Sqr(v->x) + Sqr(v->y));
if (norm == 0.0)
{
// Zero2(v)
v->x = v->y = 0.0;
return;
}
// Scale2(v, 1.0 / norm, v)
F64 scale = 1.0 / norm;
v->x = v->x * scale;
v->y = v->y * scale;
}
/* Rotate CVec2 by angle (F64) to output CVec2. */
U0 Rotate2(CVec2 *a, F64 b, CVec2 *o)
{
F64 c, s;
c = Cos(b);
s = Sin(b);
o->x = (c * a->x) - (s * a->y);
o->y = (s * a->x) - (c * a->y);
}
/* Squared distance between two CVec2. */
U0 DistanceSqr2(CVec2 *a, CVec2 *b, F64 *o)
{
*o = Sqr(b->x - b->y) + Sqr(b->y - a->y);
}
/* Distance between two CVec2. */
U0 Distance2(CVec2 *a, CVec2 *b, F64 *o)
{
*o = Sqrt(Sqr(b->x - b->y) + Sqr(b->y - a->y));
}
/* Minimum components of two CVec2. */
U0 MinVec2(CVec2 *a, CVec2 *b, CVec2 *o)
{
o->x = Min(a->x, b->x);
o->y = Min(a->y, b->y);
}
/* Maximum components of two CVec2. */
U0 MaxVec2(CVec2 *a, CVec2 *b, CVec2 *o)
{
o->x = Max(a->x, b->x);
o->y = Max(a->y, b->y);
}
/* Minimum component of CVec2. */
U0 Min2(CVec2 *a, F64 *o)
{
*o = Min(a->x, a->y);
}
/* Maximum component of CVec2. */
U0 Max2(CVec2 *a, F64 *o)
{
*o = Max(a->x, a->y);
}
/* Clamp a CVec2 to min and max values. */
U0 Clamp2(CVec2 *v, F64 minval, F64 maxval)
{
v->x = Clamp(v->x, minval, maxval);
v->y = Clamp(v->y, minval, maxval);
}
/* Linear interpolation between two CVec2. */
U0 Lerp2(CVec2 *a, CVec2 *b, F64 t, CVec2 *o)
{
CVec2 s, v;
s.x = s.y = Clamp(t, 0.0, 1.0);
// Sub2(b, a, &v)
v.x = b->x - a->x;
v.y = b->y - a->y;
// Mul2(s, v, v)
v.x *= s.x;
v.y *= s.y;
// Add(a, &v, o)
o->x = a->x + v.x;
o->y = a->y + v.y;
}

View file

@ -0,0 +1,429 @@
/* Initialize CVec3 from F64 pointer. */
U0 Vec3(F64 *a, CVec3 *o)
{
o->x = a[0];
o->y = a[1];
o->z = a[2];
}
/* Copy CVec3 into CVec3. */
U0 Copy3(CVec3 *a, CVec3 *o)
{
o->x = a->x;
o->y = a->y;
o->z = a->z;
}
/* Fill CVec3 with F64 */
U0 Fill3S(CVec3 *v, F64 val)
{
v->x = v->y = v->z = val;
}
/* Fill CIVec3 with I64 */
U0 FillI3S(CIVec3 *v, I64 val)
{
v->x = v->y = v->z = val;
}
/* Clear CVec2 with zeros. */
U0 Zero3(CVec3 *v)
{
v->x = v->y = v->z = 0.0;
}
/* Clear CVec3 with ones. */
U0 One3(CVec3 *v)
{
v->x = v->y = v->z = 1.0;
}
/* Dot product of two CVec3. */
U0 Dot3(CVec3 *a, CVec3 *b, F64 *o)
{
*o = (a->x * b->x) + (a->y * b->y) + (a->z * b->z);
}
/* Norm^2 (magnitude^2) of CVec3. */
U0 NormSqr3(CVec2 *a, F64 *o)
{
*o = Sqr(a->x) + Sqr(a->y) + Sqr(a->z);
}
/* Norm (magnitude) of CVec3. */
U0 Norm3(CVec3 *a, F64 *o)
{
*o = Sqrt(Sqr(v->x) + Sqr(v->y) + Sqr(v->z));
}
/* Manhattan Distance/Taxicab Norm, sum of component magnitudes of CVec3. */
U0 ManhattanNorm3(CVec3 *a, F64 *o)
{
*o = Abs(a->x) + Abs(a->y) + Abs(a->z);
}
/* Maximum norm (magnitude), largest magnitude of all CVec3 components. */
U0 MaxNorm3(CVec3 *a, F64 *o)
{
*o = Max(Max(Abs(a->x), Abs(a->y)), Abs(a->z));
}
/* Add CVec3 to CVec3. */
U0 Add3(CVec3 *a, CVec3 *b, CVec3 *o)
{
o->x = a->x + b->x;
o->y = a->y + b->y;
o->z = a->z + b->z;
}
/* Add CVec3 to F64. */
U0 Add3S(CVec3 *a, F64 b, CVec3 *o)
{
o->x = a->x + b;
o->y = a->y + b;
o->z = a->z + b;
}
/* Sub CVec3 from CVec3. */
U0 Sub3(CVec3 *a, CVec3 *b, CVec3 *o)
{
o->x = a->x - b->x;
o->y = a->y - b->y;
o->z = a->z - b->z;
}
/* Sub CVec3 from F64. */
U0 Sub3S(CVec3 *a, F64 b, CVec3 *o)
{
o->x = a->x - b;
o->y = a->y - b;
o->z = a->z - b;
}
/* Multiply CVec3 with CVec3. */
U0 Mul3(CVec3 *a, CVec3 *b, CVec3 *o)
{
o->x = a->x * b->x;
o->y = a->y * b->y;
o->z = a->z * b->z;
}
/* Scale CVec3 by F64. */
U0 Scale3S(CVec3 *a, F64 b, CVec3 *o)
{
o->x = a->x * b;
o->y = a->y * b;
o->z = a->z * b;
}
/* Scale CVec3 unit vector by F64. */
U0 ScaleUnit3(CVec3 *a, F64 b, CVec3 *o)
{
// Norm3(a, &norm)
F64 norm = Sqrt(Sqr(a->x) + Sqr(a->y) + Sqr(a->z));
if (norm == 0.0)
{
// Zero3(a)
a->x = 0.0;
a->y = 0.0;
a->z = 0.0;
return;
}
// Scale3(a, b / norm, o);
F64 scale = b / norm;
o->x = a->x * scale;
o->y = a->y * scale;
o->z = a->z * scale;
}
/* Divide CVec3 by CVec3. */
U0 Div3(CVec3 *a, CVec3 *b, CVec3 *o)
{
o->x = a->x / b->x;
o->y = b->y / b->y;
o->z = b->z / b->z;
}
/* Divide CVec3 by F64. */
U0 Div3S(CVec3 *a, F64 b, CVec3 *o)
{
o->x = a->x / b;
o->y = a->y / b;
o->z = a->z / b;
}
/* Square root of CVec3 components. */
U0 Sqrt3(CVec3 *a, CVec3 *o)
{
o->x = Sqrt(a->x);
o->y = Sqrt(a->y);
o->z = Sqrt(a->z);
}
/* Sign of components as -1, 0, or 1. */
U0 Sign3(CVec3 *a, CVec3 *o)
{
o->x = ((o->x > 0.0) - (val < 0.0));
o->y = ((o->y > 0.0) - (val < 0.0));
o->z = ((o->z > 0.0) - (val < 0.0));
}
/* Add CVec3 to CVec3 to output CVec3. */
U0 AddAdd3(CVec3 *a, CVec3 *b, CVec3 *o)
{
o->x += a->x + b->x;
o->y += a->y + b->y;
o->z += a->z + b->z;
}
/* Subtract CVec3 from CVec3, add to output CVec3. */
U0 SubAdd3(CVec3 *a, CVec3 *b, CVec3 *o)
{
o->x += a->x - b->x;
o->y += a->y - b->y;
o->z += a->z - b->z;
}
/* Multiply CVec3 by CVec3, add to output CVec3. */
U0 MulAdd2(CVec3 *a, CVec3 *b, CVec3 *o)
{
o->x += a->x * b->x;
o->y += a->y * b->y;
o->z += a->z * b->z;
}
/* Multiply CVec3 by F64, add to output CVec3. */
U0 MulAdd3S(CVec3 *a, F64 b, CVec3 *o)
{
o->x += a->x * b;
o->y += a->y * b;
o->z += a->z * b;
}
/* Add maximum of each CVec3 component to output CVec3. */
U0 MaxAdd3(CVec3 *a, CVec3 *b, CVec3 *o)
{
o->x += Max(a->x, b->x);
o->y += Max(a->y, b->y);
o->z += Max(a->z, b->z);
}
/* Add minimum of each CVec3 component to output CVec3. */
U0 MinAdd2(CVec3 *a, CVec3 *b, CVec3 *o)
{
o->x += Min(a->x, b->x);
o->y += Min(a->y, b->y);
o->z == Min(a->z, b->z);
}
/* Negate vector components (*-1) to output CVec3. */
U0 NegateTo2(CVec3 *a, CVec3 *o)
{
o->x = -a->x;
o->y = -a->y;
o->z = -a->z;
}
/* Negate vector components (*-1). */
U0 Negate2(CVec3 *v)
{
v->x = -v->x;
v->y = -v->y;
v->z = -v->z;
}
/* Normalize CVec3 to output CVec3. */
U0 NormalizeTo3(CVec3 *a, CVec3 *o)
{
// Norm3(a, &norm)
F64 norm = Sqrt(Sqr(a->x) + Sqr(a->y) + Sqr(a->z));
if (norm == 0.0)
{
// Zero3(o)
o->x = 0.0;
o->y = 0.0;
o->z = 0.0;
return;
}
// Scale3(a, 1.0 / norm, o)
F64 scale = 1.0 / norm;
o->x = a->x * scale;
o->y = a->y * scale;
o->z = a->z * scale;
}
/* Normalize CVec3. */
U0 Normalize3(CVec3 *v)
{
// Norm3(v, &norm)
F64 norm = Sqrt(Sqr(v->x) + Sqr(v->y) + Sqr(v->z));
if (norm == 0.0)
{
// Zero2(v)
v->x = 0.0;
v->y = 0.0;
v->z = 0.0;
return;
}
// Scale3(v, 1.0 / norm, v)
F64 scale = 1.0 / norm;
v->x = v->x * scale;
v->y = v->y * scale;
v->z = v->z * scale;
}
/* Cross product of two CVec3. */
U0 Cross3(CVec3 *a, CVec3 *b, CVec3 *o)
{
o->x = (a->y * b->z) - (a->z * b->y);
o->y = (a->z * b->x) - (a->x * b->z);
o->z = (a->x * b->y) - (a->y * b->x);
}
/* Cross product then normalize two CVec3. */
U0 CrossNormalize3(CVec3 *a, CVec3 *b, CVec3 *o)
{
// Cross3(a, b, o)
o->x = (a->y * b->z) - (a->z * b->y);
o->y = (a->z * b->x) - (a->x * b->z);
o->z = (a->x * b->y) - (a->y * b->x);
// Normalize3(o)
// Norm3(o, &norm)
F64 norm = Sqrt(Sqr(o->x) + Sqr(o->y) + Sqr(o->z));
if (norm == 0.0)
{
// Zero2(o)
o->x = o->y = o->z = 0.0;
return;
}
// Scale3(o, 1.0 / norm, o)
F64 scale = 1.0 / norm;
o->x = o->x * scale;
o->y = o->y * scale;
o->z = o->z * scale;
}
/* Angle between two vectors. */
U0 Angle3(CVec3 *a, CVec3 *b, F64 *o)
{
F64 norm, normA, normB, dot;
// Norm3(a, &normA)
normA = Sqrt(Sqr(a->x) + Sqr(a->y) + Sqr(a->z));
// Norm3(b, &normB)
normB = Sqrt(Sqr(b->x) + Sqr(v->y) + Sqr(b->z));
norm = 1.0 / (normA * normB);
// Dot(a, b, &dot)
dot = (a->x * b->x) + (a->y * b->y) + (a->z * b->z);
dot *= norm;
if (dot > 1.0)
{
*o = 0.0;
return;
}
else if (dot < -1.0)
{
*o = Pi;
return;
}
*o = ArcCos(dot);
}
/* Rotate CVec3 by angle (F64) through CVec3 axis. */
U0 Rotate3(CVec3 *a, F64 angle, CVec3 *axis, CVec3 *o)
{
CVec3 v1, v2, k;
F64 c, s, temp;
c = Cos(angle);
s = Sin(angle);
// NormalizeTo3(axis, &k);
// Norm3(axis, &temp)
temp = Sqrt(Sqr(axis->x) + Sqr(axis->y) + Sqr(axis->z));
if (temp == 0.0)
{
// Zero3(&k)
k.x = k.y = k.z = 0.0;
return;
}
// Scale3(axis, 1.0 / temp, &k)
F64 scale = 1.0 / temp;
k.x = axis->x * scale;
k.y = axis->y * scale;
k.z = axis->z * scale;
// Right Hand, Rodrigues' rotation formula:
// v = v*Cos(t) + (kxv)sin(t) + k*(k.v)(1-cos(t))
// Scale3(a, c, &v1)
v1.x = a->x * c;
v1.y = a->y * c;
v1.z = a->z * c;
// Cross3(&k, a, v2)
v2.x = (k.y * a->z) - (k.z * a->y);
v2.y = (k.z * a->x) - (k.x * a->z);
v2.z = (k.x * a->y) - (k.y * a->x);
// Scale3(&v1, s, &v2)
v2.x = v1.x * s;
v2.y = v1.y * s;
v2.z = v1.z * s;
// Add3(&v1, &v2, &v1)
v1.x += v2.x;
v1.y += v2.y;
v1.z += v2.z;
// Dot3(&k, &v, &temp)
temp = (k.x * v.x) + (k.y * v.y) + (k.z * v.z);
// Scale3(&k, temp * (1.0 - c), &v2)
temp *= (1.0 - c);
v2.x = k.x * temp;
v2.y = k.y * temp;
v2.z = k.z * temp;
// Add3(&v1, &v2, o)
o->x = v1.x + v2.x;
o->y = v1.y + v2.y;
o->z = v1.z + v2.z;
}
/* Apply Mat4 rotation matrix to CVec3. */
Rotate3M4(CVec3 *a, F64 *m, CVec3 *o)
{
CVec4 x, y, z, res;
F64 norm, scale;
// NormalizeTo4(&m[0], &x)
norm = Sqrt(Sqr(m[0][0]) + Sqr(m[0][1]) + Sqr(m[0][2]) + Sqr(m[0][3]));
if (norm == 0.0)
{
// Zero4(&x)
x.x = x.y = x.z = x.w = 0.0;
return;
}
// Scale3(v, 1.0 / norm, v)
F64 scale = 1.0 / norm;
v->x = v->x * scale;
v->y = v->y * scale;
v->z = v->z * scale;
// TODO: FINISH!!!!
}

View file

@ -0,0 +1,323 @@
/**
@ingroup Render
@brief Renders triangles to texture.
@param[in] shd Shader.
@param[in,out] frameBuf Color texture to render to.
@param[in,out] depthBuf Depth texture to render to and check against.
@param[in] mdl Model buffer, shader defines how to read this.
@param[in] uniforms Buffer of unchanging values for shader.
@param[in] nTris Number of triangles to render.
*/
U0 RenderTris(CShader *shd, CTex2D *frameBuf, CTex2D *depthBuf, U8 *mdl,
U8 *uniforms, I64 nTris)
{
Bool middle_line_drawn = FALSE;
F64 x_delta;
F64 y_delta;
F64 left_delta;
F64 right_delta;
F64 left_x;
F64 right_x;
I64 y, lX, rX;
I64 left_index, right_index;
I64 width;
I64 i, j, temp;
F64 ftemp;
F64 z; // Interpolated value to depth check
// Stores baryocentric coordinates for current fragment
F64 u, v, w;
F64 bc[3];
// Vertex coordinates. P is the point to get baryocentric coordinate for
CVec2 p, a, b, c;
CBGR24 fragColor; // Final color to write to fragment
// Calculate dimensions and allocate vertex attributes buffer
// to pass interpolated per-frag values to the fragment
// shader from the vertex shader:
F64 *vOut; // This would be like Out from GLSL, it is 3x the size of fIn (3 vertices)
F64 *fIn; // This would be like In from GLSL
I64 attrBufSize = 0;
for (i = 0; i < shd->nVertValues; i++)
{
switch (shd->vertValues[i])
{
case SHD_F64:
attrBufSize += 1;
break;
case SHD_CVEC2:
attrBufSize += 2;
break;
case SHD_CVEC3:
attrBufSize += 3;
break;
case SHD_CMat4:
attrBufSize += 16;
break;
}
}
vOut = MAlloc(attrBufSize * sizeof(F64) * 3); // 3x for 3 vertexes
fIn = MAlloc(attrBufSize * sizeof(F64)); // Single set of interpolated values
CTri cTri; // Current Triangle in NDC
CIVec2 cTriPx[3]; // Current Triangle in pixels
I64 tri; // Current Triangle Index
I64 VI[3]; // Vertex Indices
for (tri = 0; tri < nTris; tri++)
{
// Get current triangle in NDC from vertex shader
shd->VertShd(&cTri, vOut, mdl, uniforms, tri, nTris);
ftemp = 0;
ftemp += Abs(cTri.p[0].x);
ftemp += Abs(cTri.p[0].y);
ftemp += Abs(cTri.p[1].x);
ftemp += Abs(cTri.p[1].y);
ftemp += Abs(cTri.p[2].x);
ftemp += Abs(cTri.p[2].y);
// Triangle is not outside NDC range, it is on screen
//if (ftemp =< 6)
if (1 == 1)
{
// This triangle may not be in the correct order.
// y0 should be lowest in texture coordinates, then y1 and y2.
// This means y0 should be the highest in NDC coordinates.
// In VI (Vertex Indices), the array index is the index of the final point,
// and it's value is the point from the original tri it get's it's
// coordinates from.
VI[0] = 0;
VI[1] = 1;
VI[2] = 2;
if (cTri.p[VI[0]].y < cTri.p[VI[1]].y)
{
temp = VI[0];
VI[0] = VI[1];
VI[1] = temp;
}
if (cTri.p[VI[0]].y < cTri.p[VI[2]].y)
{
temp = VI[0];
VI[0] = VI[2];
VI[2] = temp;
}
if (cTri.p[VI[1]].y < cTri.p[VI[2]].y)
{
temp = VI[1];
VI[1] = VI[2];
VI[2] = temp;
}
// By now, VI[0] points to the point with the lowest
// y in texture coordinates, and VI[2] points to the highest
// Convert NDC coordinates into tex coordinates for rasterization process
cTriPx[0].x = ToI64(((cTri.p[VI[0]].x * 0.5) + 0.5) * ToF64(frameBuf->w));
cTriPx[0].y = ToI64(((-cTri.p[VI[0]].y * 0.5) + 0.5) * ToF64(frameBuf->h));
cTriPx[1].x = ToI64(((cTri.p[VI[1]].x * 0.5) + 0.5) * ToF64(frameBuf->w));
cTriPx[1].y = ToI64(((-cTri.p[VI[1]].y * 0.5) + 0.5) * ToF64(frameBuf->h));
cTriPx[2].x = ToI64(((cTri.p[VI[2]].x * 0.5) + 0.5) * ToF64(frameBuf->w));
cTriPx[2].y = ToI64(((-cTri.p[VI[2]].y * 0.5) + 0.5) * ToF64(frameBuf->h));
// Prepare F64 triangle point vectors for calculating barycentric coords later
//Userd to use VI[0]
a.x = cTriPx[0].x;
a.y = cTriPx[0].y;
b.x = cTriPx[1].x;
b.y = cTriPx[1].y;
c.x = cTriPx[2].x;
c.y = cTriPx[2].y;
// Rasterize Bottom Half (Tex coordinates, not NDC)
if (cTriPx[0].y != cTriPx[1].y)
{
x_delta = (cTriPx[1].x - cTriPx[0].x);
y_delta = (cTriPx[1].y - cTriPx[0].y);
left_delta = x_delta / y_delta;
x_delta = (cTriPx[2].x - cTriPx[0].x);
y_delta = (cTriPx[2].y - cTriPx[0].y);
right_delta = x_delta / y_delta;
if (left_delta > right_delta)
{
ftemp = left_delta;
left_delta = right_delta;
right_delta = ftemp;
}
left_x = cTriPx[0].x;
right_x = cTriPx[0].x;
middle_line_drawn = TRUE;
for (y = cTriPx[0].y; y < (cTriPx[1].y + 1); y++)
{
lX = left_x + 0.5;
rX = right_x + 0.5;
left_index = y * frameBuf->w + lX;
right_index = y * frameBuf->w + rX;
// Temporary fix, the y should just be clipped and left_x/right_x adjusted accordingly
if (TRUE)
{
// Check if x coordinate is off screen and clip it.
if (lX < 0)
{
lX = 0;
}
if (lX > frameBuf->w)
{
lX = frameBuf->w;
}
if (rX > frameBuf->w)
{
rX = frameBuf->w;
}
if (rX < 0)
{
rX = 0;
}
// For every pixel along the line, set it's color
for (i = lX; i < rX; i++)
{
// Get barycentric coordinates (u, v, w)
p.x = i;
p.y = y;
Barycentric2(&p, &a, &b, &c, &bc[VI[0]], &bc[VI[1]], &bc[VI[2]]);
z = (bc[VI[0]] * cTri.p[VI[0]].z) + (bc[VI[1]] * cTri.p[VI[1]].z) + (bc[VI[2]] * cTri.p[VI[2]].z);
if (z <= depthBuf->depthBuf[y * frameBuf->w + i])
{
// Interpolate all vOut values to fIn values for the fragment shader
for (j = 0; j < attrBufSize; j++)
{
fIn[j] = (vOut[j] * bc[0]) + (vOut[j+attrBufSize] * bc[1]) + (vOut[j+(2*attrBufSize)] * bc[2]);
}
depthBuf->depthBuf[y * frameBuf->w + i] = z;
shd->FragShd(&fragColor, fIn, uniforms);
left_index = y * frameBuf->w + i;
MemSetU32(frameBuf->rawBuf + left_index, fragColor, 1);
}
}
}
left_x += left_delta;
right_x += right_delta;
}
}
// Rasterize Top Half (Tex coordinates, not NDC)
if (cTriPx[1].y != cTriPx[2].y)
{
x_delta = -(cTriPx[1].x - cTriPx[2].x);
y_delta = (cTriPx[1].y - cTriPx[2].y);
left_delta = x_delta / y_delta;
x_delta = -(cTriPx[0].x - cTriPx[2].x);
y_delta = (cTriPx[0].y - cTriPx[2].y);
right_delta = x_delta / y_delta;
if (left_delta > right_delta)
{
ftemp = left_delta;
left_delta = right_delta;
right_delta = ftemp;
}
left_x = cTriPx[2].x;
right_x = cTriPx[2].x;
if (middle_line_drawn == TRUE)
{
cTriPx[1].y += 1;
}
a.x = cTriPx[0].x;
a.y = cTriPx[0].y;
b.x = cTriPx[1].x;
b.y = cTriPx[1].y;
c.x = cTriPx[2].x;
c.y = cTriPx[2].y;
for (y = cTriPx[2].y; y > (cTriPx[1].y - 1); y--)
{
lX = left_x + 0.5;
rX = right_x + 0.5;
left_index = y * frameBuf->w + lX;
right_index = y * frameBuf->w + rX;
// Temporary fix, the y should just be clipped and left_x/right_x adjusted accordingly
if (TRUE)
{
if (lX < 0)
{
lX = 0;
}
if (lX > frameBuf->w)
{
lX = frameBuf->w;
}
if (rX > frameBuf->w)
{
rX = frameBuf->w;
}
if (rX < 0)
{
rX = 0;
}
// For every pixel along the line, set it's color
for (i = lX; i < rX; i++)
{
// Get barycentric coordinates (u, v, w)
p.x = i;
p.y = y;
Barycentric2(&p, &a, &b, &c, &bc[VI[0]], &bc[VI[1]], &bc[VI[2]]);
z = (bc[VI[0]] * cTri.p[VI[0]].z) + (bc[VI[1]] * cTri.p[VI[1]].z) + (bc[VI[2]] * cTri.p[VI[2]].z);
if (z <= depthBuf->depthBuf[y * frameBuf->w + i])
{
// Interpolate all vOut values to fIn values for the fragment shader
for (j = 0; j < attrBufSize; j++)
{
fIn[j] = (vOut[j] * bc[0]) + (vOut[j+attrBufSize] * bc[1]) + (vOut[j+(2*attrBufSize)] * bc[2]);
}
depthBuf->depthBuf[y * frameBuf->w + i] = z;
shd->FragShd(&fragColor, fIn, uniforms);
left_index = y * frameBuf->w + i;
MemSetU32(frameBuf->rawBuf + left_index, fragColor, 1);
}
}
}
left_x += left_delta;
right_x += right_delta;
}
}
}
}
Free(vOut);
Free(fIn);
}

View file

@ -0,0 +1,97 @@
/**
@defgroup Render Render
@brief For rendering triangle arrays using vertex/fragment shaders.
*/
#define SHD_F64 1 /// @ingroup Render
#define SHD_CVEC2 2 /// @ingroup Render
#define SHD_CVEC3 3 /// @ingroup Render
#define SHD_CVEC4 4 /// @ingroup Render
#define SHD_CMat4 5 /// @ingroup Render
/**
@ingroup Render
@brief User-programmed and passed to renderer. Calculates on-screen
coordinates of every triangle vertex, as well as the color for any given
pixel being rasterized.
Render Pipeline:
1) Vertex shader feeds in triangle coordinates in NDC format
(Normalized Device Coordinates), as well as other
per-vertex values it would like to interpolate and later
feed to the frag shader.
2) Using these NDC triangle coordinates, the rasterizer
calculates pixel positions of the triangles on the texture,
and interpolates the per-vertex values given by the vertex
shader into values for the particular fragment (pixel).
3) The fragment shader is called, with the interpolated
fragment values fed in, and it calculates the color to
be drawn at that particular fragment.
*/
class CShader
{
/**
@brief The number of vertex attributes to interpolate and pass between
the vertex and fragment shader.
For example if you wanted to pass an interpolated position and UV
coordinate to the fragment shader, this value would be 2.
*/
I64 nVertValues;
/**
@brief Array of vertex attribute types that describes the format of
the vertex attributes. See SHD_ macros for types.
For example if you wanted to pass an interpolated position and UV
coordinate to the fragment shader, this array would be
{SHD_CVEC2, SHD_CVEC3}.
*/
I64 *vertValues;
/**
@brief The vertex shader serves the purpose of returning
a triangle in NDC (normalized device coordinates), as well as
returning a buffer containing other vertex attributes such as
position/normals/UVs.
@param[in,out] tri Returned triangle (in NDC).
@param[in,out] vertOutBuf Vertex attributes to be interpolated
for the frag shader. These are in format:
Vertex 0 values, Vertex 1 values, Vertex
2 values, where values has the format
defined by vertValues in CShader.
@param[in] mdlPtr The pointer to the model to calculate
the output triangle from. There is no
predefined model format, the user can
give the renderer any model they want
and interpret it in this function.
@param[in] uniforms Unchanging variables throughout the render
(ie: perspective/lighting/textures).
@param[in] iTri Index of triangle to calculate.
@param[in] nTris Total triangles being rendered. This
function only calculates one triangle
but this is given if accessing a triangle
in your model depends on this value.
*/
U0 (*VertShd)(CTri *tri, F64 *vertOutBuf, U8 *mdlPtr, U8 *uniforms,
I64 iTri, I64 nTris);
/**
@brief The fragment shader serves the purpose of calculating
the color for the current fragment (pixel) using the passed-in
interpolated vertex attributes, as well as anything else given in
the uniform buffer.
@param[in] vertBuf Interpolated vertex attributes at that frag
(ie: position, uv, normal).
@param[in] uniforms Unchanging variables throughout the render
(ie: perspective/lighting/textures).
@param[in,out] color Color calculated for this fragment.
*/
U0 (*FragShd)(CBGR24 *color, F64 *fragInBuf, U8 *uniforms);
};

View file

@ -0,0 +1,199 @@
/**
@defgroup Tex2D Texture
@brief The core of the library, almost all functions either read from
or write to textures.
*/
/**
@ingroup Tex2D
@brief Raw format is a CBGR24 rawBuf array of size w * h in row-major
order.
*/
#define TEX2D_RAW 1
/**
@ingroup Tex2D
@brief Depth format is a F64 depthBuf array of size w * h in row-major
order.
*/
#define TEX2D_DEPTH 2
/**
@ingroup Tex2D
@brief The CTex2D class
*/
class CTex2D
{
I64 type; // Type, see TEX2D_ macros above
I64 w; // Width
I64 h; // Height
I64 l; // Left offset if applicable (for use with sprite textures)
I64 t; // Top offset if applicable (for use with sprite textures)
I64 mipmaps; // Mipmaps, not currently being used
CBGR24 *rawBuf; // Raw color buffer. Size: w * h
F64 *depthBuf; // Depth buffer. Size: w * h, pixels are depth.
};
/**
@ingroup Tex2D
@brief Initialize texture.
@param[in,out] tex Uninitialized texture to initialize.
@param[in] type Type of texture. See TEX2D_ macros for options.
@param[in] w Width
@param[in] h Height
@param[in] l (Optional) left offset for use with sprite textures.
@param[in] t (Optional) top offset for use with sprite textures.
*/
U0 Tex2DInit(CTex2D *tex, I64 type, I64 w, I64 h, I64 l = 0, I64 t = 0)
{
tex->w = w;
tex->h = h;
tex->l = l;
tex->t = t;
tex->type = type;
switch (type)
{
case (TEX2D_RAW):
tex->rawBuf = MAlloc(4 * tex->w * tex->h);
break;
case (TEX2D_DEPTH):
tex->depthBuf = MAlloc(sizeof(F64) * tex->w * tex->h);
break;
}
}
/**
@ingroup Tex2D
@brief Free texture.
@param[in,out] tex Texture to free.
*/
U0 Tex2DFree(CTex2D *tex)
{
switch (tex->type)
{
case TEX2D_RAW:
Free(tex->rawBuf);
break;
case TEX2D_DEPTH:
Free(tex->depthBuf);
break;
}
}
/**
@ingroup Tex2D
@brief Fill texture with color. Only works with raw textures.
@param[in,out] tex Texture to color fill.
@param[in] color Color to fill texture with.
*/
U0 Tex2DColorFill(CTex2D *tex, CBGR24 color)
{
MemSetU32(tex->rawBuf, color, tex->w * tex->h);
}
/**
@ingroup Tex2D
@brief Reset depth texture. Set all pixels to far depth.
@param[in,out] tex Depth texture to reset.
*/
U0 Tex2DDepthReset(CTex2D *tex)
{
F64 depth = 2.0;
I64 *iDepth = &depth;
MemSetI64(tex->depthBuf, *iDepth, tex->w * tex->h);
}
/**
@ingroup Tex2D
@brief Draw texture directly to display buffer. Maps non-visible textures
like depth to a visible palette when drawing for visual debugging.
This may cause fighting with the operating system and flashing/text or
other visual updates might show through. If using this for an application,
be sure to disable the operating system from drawing to the display buffer
in GrWinUpdate32.
@param[in] tex Texture to draw to display buffer.
@param[in] x X position on screen to draw texture.
@param[in] y Y position on screen to draw texture.
*/
U0 Tex2DDebugDisp(CTex2D *tex, I64 x, I64 y)
{
// i, j = sampling x, y position on texture
I64 i, j;
// For scaling depth buffer to 8 bit color
F64 scaled;
CBGR24 color;
for (j = 0; j < tex->h; j++)
{
for (i = 0; i < tex->w; i++)
{
switch (tex->type)
{
case TEX2D_RAW:
text.fb_alias[(x + i) + (y + j) * GR_WIDTH]
= tex->rawBuf[i + j * tex->w];
break;
case TEX2D_DEPTH:
// Scaled to display 0-1024 depth
scaled = tex->depthBuf[i + j * tex->w] / 4;
color.r = scaled;
color.g = scaled;
color.b = scaled;
text.fb_alias[(x + i) + (y + j) * GR_WIDTH] = color;
break;
}
}
}
}
/**
@ingroup Tex2D
@brief Sample color from color textures at normalized UV coordinate
(0.0-1.0). Coordinates over 1.0 loop causing a repeating texture effect.
Does not handle filtering or mip maps (yet). The MemCopy's are dumb
I will replace with simply returning the color soon.
@param[in,out] col Sets color at this address to sampled color.
@param[in] tex Texture to sample from.
@param[in] u Normalized (0.0-1.0) x coordinate to sample from.
@param[in] v Normalized (0.0-1.0) y coordinate to sample from.
*/
U0 Tex2DSampleNorm(CBGR24 *col, CTex2D *tex, F64 u, F64 v)
{
I64 x = u * tex->w;
I64 y = v * tex->h;
x %= tex->w;
y %= tex->h;
MemCopy(col, &tex->rawBuf[x + y * tex->w], sizeof(CBGR24));
}
/**
@ingroup Tex2D
@brief Sample color from color textures at UV coordinate. Coordinates
over texture dimensions loop causing a repeating texture effect.
@param[in,out] col Sets color at this address to sampled color.
@param[in] u X coordinate to sample from.
@param[in] v Y coordinate to sample from.
*/
U0 Tex2DSampleCoord(CBGR24 *col, CTex2D *tex, I64 u, I64 v)
{
u %= tex->w;
v %= tex->h;
MemCopy(col, &tex->rawBuf[u + v * tex->w], sizeof(CBGR24));
}

View file

@ -0,0 +1,268 @@
/**
@ingroup Tex2D
@brief Loads Half-Life texture from WAD file.
@param[in,out] tex Unitialized texture to load into.
@param[in] wad WAD file to load from.
@param[in] texName Name of texture lump in WAD file to load.
*/
U0 Tex2DLoadWAD(CTex2D *tex, CWAD *wad, U8 *texName)
{
if (wad->type != WAD_TYPE_HL)
{
"[ERROR] CAN NOT LOAD %s TEXTURE FROM NON-HALF-LIFE WAD %s. USE LOAD
SPRITE/FLAT/WALL FOR DOOM WADS.\n", texName, wad->name;
return;
}
// Get lump handle
CWADFileLumpHL *lump;
I64 texIndex = WADFindLump(wad, texName, &lump);
if (texIndex < 0)
{
"[ERROR] CAN NOT FIND %s TEXTURE IN WAD %s\n", texName, wad->name;
return;
}
// Map texture class to WAD file buffer
CWADTexHL *wadTex = wad->fileBuf + lump->filePos;
Tex2DInit(tex, TEX2D_RAW, wadTex->w, wadTex->h);
// Map pixel array
U8 *pixel = wad->fileBuf + lump->filePos + wadTex->offsets[0];
// After the last byte of the fourth mipmap, there are two padding bytes,
// then a palette of 24-bit color (R, G, B).
U8 *palette = wad->fileBuf + lump->filePos + wadTex->offsets[3] +
((wadTex->w * wadTex->h) / 64) + 2;
// 1/64 here is the relative size of 4th mip map
I64 i;
CBGR24 color;
color.pad = 255; // Alpha
for (i = 0; i < wadTex->w * wadTex->h; i++)
{
color.r = palette[pixel[i] * 3];
color.g = palette[(pixel[i] * 3) + 1];
color.b = palette[(pixel[i] * 3) + 2];
tex->rawBuf[i] = color;
// Full blue pixels are transparent
if (color == 0xFF0000FF)
tex->rawBuf[i].pad = 0;
}
}
/**
@internal
@ingroup Tex2D
@brief Loads DOOM patch at memory location into position on texture.
Relevant locations on texture should be initialized with a transparent
alpha byte.
@param[in,out] tex Initialized texture to load into.
@param[in] patch Memory location of patch to load from.
@param[in] palette Array of 256 colors.
@param[in] l Left (x) offset.
@param[in] t Top (y) offset.
*/
U0 Tex2DLoadWADPatch(CTex2D *tex, CWADPatch *patch, CBGR24 *palette,
I64 l, I64 t)
{
I64 x, y;
CWADPost *post; // Current post being parsed.
// Direct pointer addition gives wierd results so these are
// intermediate pointers:
I64 patchAddr = patch;
I64 cursor;
// Iterate through every column in patch
for (x = 0; x < patch->w; x++)
{
// Point post to first post in current column
cursor = patchAddr + patch->columnOffsets[x];
post = cursor;
// Post with offset 255 is last post in column and is empty
while (post->yOffset != 255)
{
// Draw every pixel in post to texture buffer
for (y = 0; y < post->length; y++)
{
tex->rawBuf[(x + l) + (y + t + post->yOffset) * tex->w]
= palette[post->pixels[y]];
}
// Point post to next post in column
cursor += post->length + 4; // 3 starting bytes + last pad byte
post = cursor;
}
}
}
/**
@ingroup Tex2D
@brief Loads DOOM sprite from WAD file.
@param[in,out] tex Unitialized texture to load into.
@param[in] wad WAD file to load from.
@param[in] sprName Name of sprite in WAD file to load.
*/
U0 Tex2DLoadWADSprite(CTex2D *tex, CWAD *wad, U8 *sprName)
{
if (wad->type != WAD_TYPE_DOOM)
{
"[ERROR] CAN NOT LOAD %s SPRITE FROM NON-DOOM %s\n", sprName, wad->name;
return;
}
// Get lump handle
CWADFileLumpDoom *lump;
I64 sprIndex = WADFindLump(wad, sprName, &lump);
if (sprIndex < 0)
{
"[ERROR] CAN NOT FIND %s SPRITE IN %s\n", sprName, wad->name;
return;
}
// Map patch class to sprite lump (which is in patch format)
CWADPatch *patch = wad->fileBuf + lump->filePos;
Tex2DInit(tex, TEX2D_RAW, patch->w, patch->h, patch->l, patch->t);
Tex2DColorFill(tex, 0); // To set alpha to 0 since patch's don't draw
// the transparent pixels, only opaque ones.
Tex2DLoadWADPatch(tex, patch, wad->paletteBuf, 0, 0);
}
/**
@ingroup Tex2D
@brief Loads DOOM wall texture from WAD file.
@param[in,out] tex Uninitialized texture to load into.
@param[in] wad WAD file to load from.
@param[in] wallName Name of wall in WAD file to load.
*/
U0 Tex2DLoadWADWall(CTex2D *tex, CWAD *wad, U8 *wallName)
{
}
/**
@internal
@ingroup Tex2D
@brief BMP file header.
*/
class CBMPHeader
{
U8 szVersion[2]; // Should have 'BM' signature
U32 nSize; // File size in bytes
U32 pad; // Unused
U32 nOffset; // Offset from beginning of file to data;
/* Info header is right after first header, so it is merged into this class */
U32 nInfoSize; // Size of this info part of the header (=40)
U32 nWidth; // Image width in pixels
U32 nHeight; // Image height in pixels
U16 nPlanes; // Number of planes (=1)
U16 nPxBits; // Number of bits per pixel. This also indicates palette method:
// 1-bit: Monochrome
// 4-bit: 16-color palette
// 8-bit: 256-color palette
// 16-bit: 65565 colors
// 24-bit: 16M colors
U32 nCompression; // Type of compression:
// 0: BI_RGB no-compression
// 1: BI_RLE8 8-bit RLE encoding
// 2: BI_RLE4 4-bit RLE encoding
U32 nImageSize; // Size of image if compressed, (can =0 if not compressed)
U32 nXPxPerM; // Horizontal resolution, pixels per meter
U32 nYPxPerM; // Vertical resolution, pixels per meter
U32 nColors; // Number of actually used colors (ie. 256 for 8-bit color)
U32 nImptColors; // Number of important colors (=0 for all)
};
/**
@ingroup Tex2D
@brief Loads BMP image.
Supports standard uncompressed 24-bit color BMP images.
@param[in,out] tex Uninitialized texture to load into.
@param[in] fname File name of BMP.
*/
U0 Tex2DLoadBMP(CTex2D *tex, U8 *fname, Bool mask = FALSE,
Bool invert = TRUE)
{
U8 *bmp = FileRead(fname);
// Map locations in buffer;
CBMPHeader *info = bmp;
//if (StrMatch(bmp->szVersion, "BM") == 0)
if (info->szVersion[0] != 'B' && info->szVersion[1] != 'M')
{
"[ERROR] %s IS NOT A VALID BMP FILE!\n", fname;
return;
}
if (info->nPxBits != 24 || info->nCompression != 0)
{
"[ERROR] %s IS NOT A 24-BIT UNCOMPRESSED BMP!\n", fname;
return;
}
// Each pixel is 3 bytes in 24-bit BMP, however CTex2D uses CBGR24
// which contains a final padding bit (32-bits per pixel). The rows
// also increment in the opposite direction.
I64 imgPointer = bmp + info->nOffset;
I64 xPx, yPx;
// For checking if a color channel is greater than 0 for masks
U8 channel;
if (mask)
{
/*
// Initialize with MASK format for 1-bit non-compressed color
Tex2DInit(tex, TEX2D_MASK, info->nWidth, info->nHeight);
for (yPx = 0; yPx < info->nHeight; yPx++)
{
for (xPx = 0; xPx < info->nWidth; xPx++)
{
channel = *(imgPointer + (xPx + info->nWidth *
(info->nHeight - yPx)) * 3);
if ((channel == 0 && invert = TRUE) ||
(channel > 0 && invert = FALSE))
{
tex->maskBuf[(xPx + info->nWidth * yPx) / 8] | (1 << (xPx % 8));
}
}
}
*/
}
else
{
// Initialize with RAW format for 24-bit non-compressed color
Tex2DInit(tex, TEX2D_RAW, info->nWidth, info->nHeight);
for (yPx = 0; yPx < info->nHeight; yPx++)
{
for (xPx = 0; xPx < info->nWidth; xPx++)
{
MemCopy(&tex->rawBuf[xPx + info->nWidth * yPx],
imgPointer + (xPx + info->nWidth * (info->nHeight - yPx))
* 3, 3);
}
}
}
}

View file

@ -0,0 +1,263 @@
/**
@internal
@ingroup Doom
@brief Hash table type for Doom texture hash.
*/
#define HTT_DOOM_TEX 420
/**
@internal
@ingroup Doom
@brief Doom texture hash table size.
*/
#define DOOM_TEX_TABLE_SIZE 256
/**
@internal
@ingroup Doom
@brief Hash for quick access of textures by name.
*/
class CHashDoomTex : CHash
{
CTex2D tex;
};
/**
@ingroup Doom
@brief Runtime Doom map.
*/
class CDoomMap
{
I64 pad;
CDoomVertex *vertexes;
I64 nVertexes;
CDoomSide *sides;
I64 nSides;
CDoomLine *lines;
I64 nLines;
// CHashTable *texTable; // Hash table for quick access of textures
};
/**
@internal
@ingroup Doom
@brief Load blockmap from WAD into Doom map. See CDoomBBox.
@param[in,out] map Doom map to load into.
@param[in] wad WAD to load from.
@param[in] lumpIndex Index of BLOCKMAP lump in WAD.
*/
U0 DoomMapLoadBlockmap(CDoomMap *map, CWAD *wad, I64 lumpIndex)
{
}
/**
@internal
@ingroup Doom
Load vertexes from WAD into Doom map. See CDoomVertex.
@param[in,out] map Doom map to load into.
@param[in] wad WAD to load from.
@param[in] lumpIndex Index of VERTEXES lump in WAD.
*/
U0 DoomMapLoadVertexes(CDoomMap *map, CWAD *wad, I64 lumpIndex)
{
CWADFileLumpDoom *lump = &wad->doomLumps[lumpIndex];
if (StrNICompare("VERTEXES", lump->name, 8) != 0)
{
"[ERROR] EXPECTED VERTEXES LUMP INDEX DOES NOT POINT TO A
VERTEXES LUMP\n";
return;
}
// Map WAD vertex array
CWADVertex *verts = wad->fileBuf + lump->filePos;
// Calculate and update number of vertexes
I64 nVerts = lump->size / sizeof(CWADVertex);
map->nVertexes = nVerts;
// Allocate memory for map vertexes
map->vertexes = MAlloc(sizeof(CDoomVertex) * nVerts);
// Load I16 vertexes to I64 fixed point
I32 xIntermediate;
I32 yIntermediate;
I64 i;
for (i = 0; i < nVerts; i++)
{
// Load I16 to I32 to preserve sign at MSB when shifting 32 bits left
// for I64 fixed point conversion.
xIntermediate = verts[i].x;
yIntermediate = verts[i].y;
map->vertexes[i].x = xIntermediate << 32;
map->vertexes[i].y = yIntermediate << 32;
}
}
/**
@internal
@ingroup Doom
@brief Load sectors from WAD into Doom map. See CDoomSector.
@param[in,out] map Doom map to load into.
@param[in] wad WAD to load from.
@param[in] lumpIndex Index of SECTORS lump in WAD.
*/
U0 DoomMapLoadSectors(CDoomMap *map, CWAD *wad, I64 lumpIndex)
{
}
/**
@internal
@ingroup Doom
@brief Load sides from WAD into Doom map. See CDoomSide.
@param[in,out] map Doom map to load into.
@param[in] wad WAD to load from.
@param[in] lumpIndex Index of SIDEDEFS lump in WAD.
*/
U0 DoomMapLoadSides(CDoomMap *map, CWAD *wad, I64 lumpIndex)
{
CWADFileLumpDoom *lump = &wad->doomLumps[lumpIndex];
if (StrNICompare("SIDEDEFS", lump->name, 8) != 0)
{
"[ERROR] EXPECTED SIDEDEFS LUMP INDEX DOES NOT POINT TO A
SIDEDEFS LUMP\n";
return;
}
// Map WAD sidedef array
CWADSidedef *sidedefs = wad->fileBuf + lump->filePos;
// Calculate and update number of sidedefs
I64 nSidedefs = lump->size / sizeof(CWADSidedef);
map->nSides = nSidedefs;
// Allocate memory for map sides
map->sides = MAlloc(sizeof(CDoomSide) * nSidedefs);
I64 i;
for (i = 0; i < nSidedefs; i++)
{
map->sides[i].xOffset = sidedefs[i].xOffset;
map->sides[i].yOffset = sidedefs[i].yOffset;
/* Todo - Handle wall texture loading */
}
}
/**
@internal
@ingroup Doom
@brief Load lines from WAD into Doom map. See CDoomLine.
@param[in,out] map Doom map to load into.
@param[in] wad WAD to load from.
@param[in] lumpIndex Index of LINEDEFS lump in WAD.
*/
U0 DoomMapLoadLines(CDoomMap *map, CWAD *wad, I64 lumpIndex)
{
CWADFileLumpDoom *lump = &wad->doomLumps[lumpIndex];
if (StrNICompare("LINEDEFS", lump->name, 8) != 0)
{
"[ERROR] EXPECTED LINEDEFS LUMP INDEX DOES NOT POINT TO A
LINEDEFS LUMP\n";
return;
}
// Map WAD linedefs array
CWADLinedef *linedefs = wad->fileBuf + lump->filePos;
// Calculate and update number of linedefs
I64 nLinedefs = lump->size / sizeof(CWADLinedef);
map->nLines = nLinedefs;
// Allocate memory for map linedefs
map->lines = MAlloc(sizeof(CDoomLine) * nLinedefs);
I64 i;
for (i = 0; i < nLinedefs; i++)
{
map->lines[i].v1 = &map->vertexes[linedefs[i].v1];
map->lines[i].v2 = &map->vertexes[linedefs[i].v2];
map->lines[i].frontSide = &map->sides[linedefs[i].frontSidedef];
map->lines[i].backSide = &map->sides[linedefs[i].backSidedef];
}
}
/**
@internal
@ingroup Doom
@brief Builds sector line lists and subsector numbers. Finds block
bounding boxes for sectors.
@param[in,out] map Map to modify.
*/
U0 DoomMapGroupLines(CDoomMap *map)
{
// Look up sector number for each subsector
}
/**
@ingroup Doom
@brief Load DOOM map from WAD file.
@param[in,out] map Uninitialized Doom map to load into.
@param[in] wad WAD to load from.
@param[in] mapName Map from WAD to load (max length is 8 characters).
*/
U0 DoomMapLoad(CDoomMap *map, CWAD *wad, U8 *mapName)
{
I64 mapLumpIndex = WADFindLump(wad, mapName, NULL);
if (mapLumpIndex < 0)
{
"[ERROR] UNABLE TO FIND MAP %s IN WAD\n", mapName;
return;
}
// Prepare texture hash table
// map->texTable = HashTableNew(DOOM_TEX_TABLE_SIZE);
//I64 thingsIndex = mapLumpIndex + 1;
I64 vertexesIndex = mapLumpIndex + 4;
DoomMapLoadVertexes(map, wad, vertexesIndex);
I64 sidedefsIndex = mapLumpIndex + 3;
DoomMapLoadSides(map, wad, sidedefsIndex);
I64 linedefsIndex = mapLumpIndex + 2;
DoomMapLoadLines(map, wad, linedefsIndex);
//I64 segsIndex = mapLumpIndex + 5;
//I64 subsectorsIndex = mapLumpIndex + 6;
//I64 rejectIndex = mapLumpIndex + 7;
//I64 blockmapIndex = mapLumpIndex + 8;
}
/**
@ingroup Doom
@brief Free Doom map.
@param[in,out] map Doom map to free.
*/
U0 DoomMapFree(CDoomMap *map)
{
// Free(map->vertexes);
// Free(map->lines);
// Free(map->sides);
}

View file

@ -0,0 +1,125 @@
/**
@defgroup Doom Doom
@brief Functions for loading Doom maps from WADs and rendering them.
*/
/**
@ingroup Doom
@brief Fixed point 2D vertex.
*/
class CDoomVertex
{
I64 x;
I64 y;
};
/**
@internal
@ingroup Doom
@brief Fixed point 2D bounding box.
*/
class CDoomBBox
{
I64 x1;
I64 y1;
I64 x2;
I64 y2;
};
/**
@internal
@ingroup Doom
@brief A sector is a 2D section of the map.
*/
class CDoomSector
{
I64 floorH; // Floor height
I64 ceilingH; // Ceiling height
CTex2D *floorTex;
CTex2D *ceilingTex;
I64 lightLevel;
I64 special;
I16 tag;
I64 nLines; // Total lines associated with sector
//CDoomLine **lines; // Array of line pointers
CDoomBBox blockBox[4]; // Bounding box for height changes
};
/**
@internal
@ingroup Doom
@brief A side contains the textures applied to a line (wall).
*/
class CDoomSide
{
I64 xOffset;
I64 yOffset;
CTex2D *upperTex;
CTex2D *lowerTex;
CTex2D *middleTex;
CDoomSector *sectorFacing;
};
/**
@internal
@ingroup Doom
@brief Lines make up the shape of the map. A one sided wall is a
solid wall, while a two sided wall is a boundary between sectors.
*/
class CDoomLine
{
CDoomVertex *v1;
CDoomVertex *v2;
CDoomSide *frontSide;
CDoomSide *backSide;
};
/**
@internal
@ingroup Doom
@brief Clipped line that is used to make up subsectors.
*/
class CDoomSeg
{
}
/**
@internal
@ingroup Doom
@brief List of segs indicating some or all visible walls that define
a convex BSP leaf.
*/
class CDoomSubSector
{
CDoomSector *sector;
I64 nLines;
I64 firstLine;
};
#define NF_SUBSECTOR 0x8000
/**
@internal
@ingroup Doom
@brief Splits level down a line. On either side of the line is either
another child node or a BSP leaf (subsector).
*/
class CDoomNode
{
I64 x; // Partition start coordinates
I64 y;
I64 xChange; // Change from start to end of partition line
I64 yChange;
CDoomBBox rightBox;
CDoomBBox leftBox;
CDoomNode *rightChild;
CDoomNode *leftChild;
};

View file

@ -0,0 +1,207 @@
/**
@internal
@ingroup WAD
@brief Half-Life WAD type.
*/
#define WAD_TYPE_HL 1
/**
@internal
@ingroup WAD
@brief Doom WAD type.
*/
#define WAD_TYPE_DOOM 2
/**
@internal
@ingroup WAD
@brief Hash table type for lump hash.
*/
#define HTT_LUMP 69
/**
@internal
@ingroup WAD
@brief Hash for quick access of lump pointer and index by name.
*/
class CHashLump : CHash
{
CWADFileLump *lump; // Pointer to lump
// Access with lump->doom/lump->hl
I64 lumpIndex; // Index of lump in WAD
};
/**
@ingroup WAD
@brief Class for WAD currently in memory.
Has easy access handles and a hash table to quickly find lumps.
*/
class CWAD
{
U8 *name;
U8 *fileBuf;
CWADInfo *info; // Type, size, pointer to lumps
CWADFileLumpDoom *doomLumps;// Quick access doom lumps
CWADFileLumpHL *hlLumps; // Quick access half life lumps
I64 type; // WAD type
CHashTable *lumpTable; // Hash table for quick access of
// lumps by name.
CHashLump *hashLumps; // Hashes for lumpTable.
CBGR24 *paletteBuf; // Color palette 0 for texture loading if doom
};
/**
@ingroup WAD
@brief Finds lump with name and returns it's index in the WAD. Also
points input lump pointer to it if found.
@param[in] wad WAD to search.
@param[in] name Lump name to find.
@param[in,out] lump Points to lump if found.
@return Lump index in WAD. -1 if not found.
*/
I64 WADFindLump(CWAD *wad, U8 *name, CWADFileLump **lump = NULL)
{
CHashLump *lumpHash;
lumpHash = HashFind(name, wad->lumpTable, HTT_LUMP);
if (lumpHash != NULL)
{
if (lump != NULL)
*lump = lumpHash->lump;
return lumpHash->lumpIndex;
}
else
{
return -1;
}
}
/**
@ingroup WAD
@brief Loads WAD file.
@param[in,out] wad Uninitialized WAD to initialize.
@param[in] fname File name of WAD.
*/
U0 WADLoad(CWAD *wad, U8 *fname)
{
wad->fileBuf = FileRead(fname);
wad->name = StrNew(fname);
// For palette loading if doom WAD
CWADFileLumpDoom *paletteLump;
U8 *paletteColor;
// Map locations in buffer
wad->info = wad->fileBuf;
// Allocate hash table
wad->lumpTable = HashTableNew(wad->info->nLumps); // Table
wad->hashLumps = CAlloc(wad->info->nLumps * // Hashes
sizeof(CHashLump));
I64 i;
// Check version and proceed accordingly
U32 *type = wad->info->type; // Cast to U32
// 'WAD3': Half Life 'WAD2': Quake
if (*type == 0x33444157 || *type == 0x32444157)
{
wad->type = WAD_TYPE_HL;
// Map lumps to buffer
wad->hlLumps = wad->fileBuf + wad->info->lumpOffset;
for (i = 0; i < wad->info->nLumps; i++)
{
// Copy name to hash
wad->hashLumps[i].str = CAlloc(17); // 16 + NULL
MemCopy(wad->hashLumps[i].str,
wad->hlLumps[i].name, 16);
// Set hash type
wad->hashLumps[i].type = HTT_LUMP;
// Link lump to hash
wad->hashLumps[i].lump = &wad->hlLumps[i];
// Set lump index in hash to this index
wad->hashLumps[i].lumpIndex = i;
// Add hash to table
HashAdd(&wad->hashLumps[i], wad->lumpTable);
}
return;
}
// 'IWAD': Doom Internal 'PWAD': Doom Patch
if (*type == 0x44415749 || *type == 0x44415750)
{
wad->type = WAD_TYPE_DOOM;
// Map lumps to buffer
wad->doomLumps = wad->fileBuf + wad->info->lumpOffset;
for (i = 0; i < wad->info->nLumps - 10; i++)
{
// Copy name to hash
wad->hashLumps[i].str = CAlloc(9); // 8 + NULL
MemCopy(wad->hashLumps[i].str,
wad->doomLumps[i].name, 8);
// Set hash type
wad->hashLumps[i].type = HTT_LUMP;
// Link lump to hash
wad->hashLumps[i].lump = &wad->doomLumps[i];
// Set lump index in hash to this index
wad->hashLumps[i].lumpIndex = i;
// Add hash to table
HashAdd(&wad->hashLumps[i], wad->lumpTable);
}
// Load palette 0 for texture loading later if it exists
if (WADFindLump(wad, "PLAYPAL", &paletteLump) != -1)
{
wad->paletteBuf = MAlloc(sizeof(CBGR24) * 256);
paletteColor = wad->fileBuf + paletteLump->filePos;
// Load each 3-byte RGB color into 4 byte BGRA palette
for (i = 0; i < 256; i++)
{
wad->paletteBuf[i].r = paletteColor[i * 3];
wad->paletteBuf[i].g = paletteColor[i * 3 + 1];
wad->paletteBuf[i].b = paletteColor[i * 3 + 2];
wad->paletteBuf[i].pad = 255; // Alpha
}
}
return;
}
// Type not recognized
U64 typeStr = 0;
MemCopy(&typeStr, wad->type, 4);
"[ERROR] %s WAD TYPE NOT RECOGNIZED: %s\n", typeStr;
}
/**
@ingroup WAD
@brief Free WAD.
@param[in,out] wad WAD to free.
*/
U0 WADFree(CWAD *wad)
{
Free(wad->lumpTable->body);
Free(wad->lumpTable);
Free(wad->hashLumps);
Free(wad->fileBuf);
}

View file

@ -0,0 +1,283 @@
/**
@defgroup WAD WAD
@brief WAD file format management and parsing. Supports DOOM and
Half-Life WADs.
*/
/**
@internal
@ingroup WAD
@brief WAD file header.
*/
class CWADInfo
{
U8 type[4]; // Type of WAD, like IWAD/PWAD/WAD3
I32 nLumps; // Number of lumps
I32 lumpOffset; // Offset to lump
};
/**
@ingroup WAD
@brief DOOM file lump. These point to "lumps" or directories in the WAD.
*/
class CWADFileLumpDoom
{
I32 filePos; // Relative offset
I32 size;
U8 name[8];
};
/**
@ingroup WAD
@brief Half-Life file lump. These point to "lumps" or directories in the
WAD.
*/
class CWADFileLumpHL
{
I32 filePos; // Relative offset
I32 diskSize; // Size of lump (compressed)
I32 size; // Uncompressed lump size
I8 type;
I8 compression; // 0 if none
I16 pad;
U8 name[16];
};
/**
@ingroup WAD
@brief Union of Half-Life and DOOM lump classes to return as a pointer
from general purpose WAD functions like WADFindLump.
*/
union CWADFileLump
{
CWADFileLumpDoom doom;
CWADFileLumpHL hl;
};
/**
@internal
@ingroup WAD
@brief Thing element from a DOOM WAD THINGS lump.
Describes an entity.
*/
class CWADThing
{
I16 x;
I64 y;
I16 angle;
I16 type;
I16 flags;
};
/**
@internal
@ingroup WAD
@brief Linedef element from a DOOM WAD LINEDEFS lump.
Describes a line that makes up a wall/sector boundary on the map.
*/
class CWADLinedef
{
I16 v1; // Vertex 1
I16 v2; // Vertex 2
I16 flags;
I16 type;
I16 sectorTag;
I16 frontSidedef; // Sidedefs hold texture data for each side of linedef
I16 backSidedef;
};
/**
@internal
@ingroup WAD
@brief Sidedef element from a DOOM WAD SIDEDEFS lump.
Describes a side of a line (wall) and what textures it uses as well as
what sector it faces.
*/
class CWADSidedef
{
I16 xOffset; // Texture x offset
I16 yOffset; // Texture y offset
U8 upperTex[8]; // These are found in TEXTUREx lumps
U8 lowerTex[8];
U8 middleTex[8];
I16 sectorFaces; // Sector this sidedef faces
};
/**
@internal
@ingroup WAD
@brief Vertex element from a DOOM WAD VERTEXES lump.
*/
class CWADVertex
{
I16 x;
I16 y;
};
/**
@internal
@ingroup WAD
@brief Segment element from a DOOM WAD SEGS lump.
Describes a segment of a line that makes up the outline of a subsector
(convex BSP leaf).
*/
class CWADSeg
{
I16 v1;
I16 v2;
I16 angle;
I16 linedef;
I16 direction;
I16 offset;
};
/**
@internal
@ingroup WAD
@brief Sector element from a DOOM WAD SECTORS lump.
Describes a 2D region of the map.
*/
class CWADSector
{
I16 floorHeight;
I16 ceilingHeight;
U8 floorTex[8];
U8 ceilingTex[8];
I16 lightLevel;
I16 flags;
I16 tag;
};
/**
@internal
@ingroup WAD
@brief Sub-sector element from a DOOM WAD SSECTORS lump.
Describes a convex BSP leaf, meaning a convex sub section of a sector.
*/
class CWADSubSector
{
I16 nLinedefs;
I16 firstLinedef;
};
/**
@internal
@ingroup WAD
@brief Node element from a DOOM WAD NODES lump
Describes a node on a BSP tree. Each node splits a region of the map into
two along a line, with a left/right side child which can either be another
node or a subsector.
*/
class CWADNode
{
I16 x;
I16 y;
};
/**
@internal
@ingroup WAD
@brief DOOM Patch texture header.
Points to columns which are variable size arrays of CWADPost. This is a
variable length class.
*/
class CWADPatch
{
U16 w;
U16 h;
I16 l; // Offsets to shift origin point when drawing
I16 t;
U32 columnOffsets[1]; // Array of offsets (relative to header) of size
// width. If columns are identical they may point
// to the same column in the file.
};
/**
@internal
@ingroup WAD
@brief DOOM Post.
A post is a vertical segment of opaque pixels in the column of a patch
texture. There may be multiple of these posts in a column, one after the
other, with the end of a column being signifiged by a post with an offset
of 255. This is a variable length class.
*/
class CWADPost
{
U8 yOffset; // Offset from start of column. This is 255 if
// signaling end of column.
U8 length; // Length is bytes/pixels
U8 pad;
U8 pixels[1]; // Size is equal to length. Each pixel points to a color
// in the color palette.
// Technically another U8 pad comes here but pixels is variable length
};
/**
@internal
@ingroup WAD
@brief Header to DOOM TEXTUREx lumps.
*/
class CWADTexHeader
{
I32 nTextures; // Number of textures in TEXTUREx lump
I32 offsets[1]; // Offsets to CWADMapTex's from start of this class
};
/**
@internal
@ingroup WAD
@brief Information about DOOM patch and where to find it in the PNAMES
lump.
*/
class CWADMapPatch
{
I16 l; // Left offset (x origin)
I16 t; // Top offset (y origin)
I16 patch; // Patch number listed in PNAMES lump
I16 stepdir; // Obsolete, ignored by all DOOM versions
I16 colormap; // Obsolete, ignored by all DOOM versions
};
/**
@internal
@ingroup WAD
@brief Texture in a DOOM TEXTUREx lump.
A texture is composed of multiple patches. However it would have been
too simple for this to point to these patches directly, instead it points
to CWADMapPatch which describes where the patch is found in the PNAMES
lump.
*/
class CWADMapTex
{
U8 name[8];
I32 masked; // Boolean
I16 width;
U16 height;
U8 columnDir[4]; // Obsolete, ignored by all DOOM versions
I16 patchCount; // Number of patches that make up texture
CWADMapPatch patches[1]; // Size dependent on patchCount
};
/**
@internal
@ingroup WAD
@brief Header to a Half-Life texture lump.
*/
class CWADTexHL
{
U8 name[16];
U32 w;
U32 h;
U32 offsets[4]; // Relative offset to each mip map
};

View file

@ -24,4 +24,5 @@ LBts(&sys_run_level, RLf_DOC);
#include "ZDefine"
#include "WallPaper"
#include "ZMouse"
#include "CosmicGL/MakeCosmicGL"
Cd("..");;