little fix to premakefile

This commit is contained in:
aap
2020-04-28 17:24:26 +02:00
parent a312007893
commit c39759f83c
14 changed files with 8 additions and 5 deletions

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

134
tools/playground/camera.cpp Normal file
View File

@@ -0,0 +1,134 @@
#include <cstdio>
#include <cassert>
#include <rw.h>
#define PI 3.14159265359f
#include "camera.h"
using rw::Quat;
using rw::V3d;
void
Camera::update(void)
{
if(m_rwcam){
m_rwcam->setNearPlane(m_near);
m_rwcam->setFarPlane(m_far);
m_rwcam->setFOV(m_fov, m_aspectRatio);
rw::Frame *f = m_rwcam->getFrame();
if(f){
V3d forward = normalize(sub(m_target, m_position));
V3d left = normalize(cross(m_up, forward));
V3d nup = cross(forward, left);
f->matrix.right = left; // lol
f->matrix.up = nup;
f->matrix.at = forward;
f->matrix.pos = m_position;
f->matrix.optimize();
f->updateObjects();
}
}
}
void
Camera::setTarget(V3d target)
{
m_position = sub(m_position, sub(m_target, target));
m_target = target;
}
float
Camera::getHeading(void)
{
V3d dir = sub(m_target, m_position);
float a = atan2(dir.y, dir.x)-PI/2.0f;
return m_localup.z < 0.0f ? a-PI : a;
}
void
Camera::turn(float yaw, float pitch)
{
V3d dir = sub(m_target, m_position);
Quat r = Quat::rotation(yaw, rw::makeV3d(0.0f, 0.0f, 1.0f));
dir = rotate(dir, r);
m_localup = rotate(m_localup, r);
V3d right = normalize(cross(dir, m_localup));
r = Quat::rotation(pitch, right);
dir = rotate(dir, r);
m_localup = normalize(cross(right, dir));
if(m_localup.z >= 0.0) m_up.z = 1.0;
else m_up.z = -1.0f;
m_target = add(m_position, dir);
}
void
Camera::orbit(float yaw, float pitch)
{
V3d dir = sub(m_target, m_position);
Quat r = Quat::rotation(yaw, rw::makeV3d(0.0f, 0.0f, 1.0f));
dir = rotate(dir, r);
m_localup = rotate(m_localup, r);
V3d right = normalize(cross(dir, m_localup));
r = Quat::rotation(-pitch, right);
dir = rotate(dir, r);
m_localup = normalize(cross(right, dir));
if(m_localup.z >= 0.0) m_up.z = 1.0;
else m_up.z = -1.0f;
m_position = sub(m_target, dir);
}
void
Camera::dolly(float dist)
{
V3d dir = setlength(sub(m_target, m_position), dist);
m_position = add(m_position, dir);
m_target = add(m_target, dir);
}
void
Camera::zoom(float dist)
{
V3d dir = sub(m_target, m_position);
float curdist = length(dir);
if(dist >= curdist)
dist = curdist-0.01f;
dir = setlength(dir, dist);
m_position = add(m_position, dir);
}
void
Camera::pan(float x, float y)
{
V3d dir = normalize(sub(m_target, m_position));
V3d right = normalize(cross(dir, m_up));
V3d localup = normalize(cross(right, dir));
dir = add(scale(right, x), scale(localup, y));
m_position = add(m_position, dir);
m_target = add(m_target, dir);
}
float
Camera::distanceTo(V3d v)
{
return length(sub(m_position, v));
}
Camera::Camera()
{
m_position.set(0.0f, 6.0f, 0.0f);
m_target.set(0.0f, 0.0f, 0.0f);
m_up.set(0.0f, 0.0f, 1.0f);
m_localup = m_up;
m_fov = 70.0f;
m_aspectRatio = 1.0f;
m_near = 0.1f;
m_far = 100.0f;
m_rwcam = NULL;
}

26
tools/playground/camera.h Normal file
View File

@@ -0,0 +1,26 @@
class Camera
{
public:
rw::Camera *m_rwcam;
rw::V3d m_position;
rw::V3d m_target;
rw::V3d m_up;
rw::V3d m_localup;
float m_fov, m_aspectRatio;
float m_near, m_far;
void setTarget(rw::V3d target);
float getHeading(void);
void turn(float yaw, float pitch);
void orbit(float yaw, float pitch);
void dolly(float dist);
void zoom(float dist);
void pan(float x, float y);
void update(void);
float distanceTo(rw::V3d v);
Camera(void);
};

181
tools/playground/font.cpp Normal file
View File

@@ -0,0 +1,181 @@
#include <rw.h>
#include <skeleton.h>
using namespace rw;
struct Font
{
Texture *tex;
int32 glyphwidth, glyphheight;
int32 numglyphs;
};
Font vga = { nil, 8, 16, 256 };
Font bios = { nil, 8, 8, 256 };
Font *curfont = &bios;
#define NUMCHARS 100
uint16 indices[NUMCHARS*6];
RWDEVICE::Im2DVertex vertices[NUMCHARS*4];
int32 curVert;
int32 curIndex;
void
printScreen(const char *s, float32 x, float32 y)
{
char c;
Camera *cam;
RWDEVICE::Im2DVertex *vert;
uint16 *ix;
curVert = 0;
curIndex = 0;
float32 u, v, du, dv;
float recipZ;
cam = (Camera*)engine->currentCamera;
vert = &vertices[curVert];
ix = &indices[curIndex];
du = curfont->glyphwidth/(float32)curfont->tex->raster->width;
dv = curfont->glyphheight/(float32)curfont->tex->raster->height;
recipZ = 1.0f/cam->nearPlane;
while(c = *s){
if(c >= curfont->numglyphs)
c = 0;
u = (c % 16)*curfont->glyphwidth / (float32)curfont->tex->raster->width;
v = (c / 16)*curfont->glyphheight / (float32)curfont->tex->raster->height;
vert->setScreenX(x);
vert->setScreenY(y);
vert->setScreenZ(rw::im2d::GetNearZ());
vert->setCameraZ(cam->nearPlane);
vert->setRecipCameraZ(recipZ);
vert->setColor(255, 255, 255, 255);
vert->setU(u, recipZ);
vert->setV(v, recipZ);
vert++;
vert->setScreenX(x+curfont->glyphwidth);
vert->setScreenY(y);
vert->setScreenZ(rw::im2d::GetNearZ());
vert->setCameraZ(cam->nearPlane);
vert->setRecipCameraZ(recipZ);
vert->setColor(255, 255, 255, 255);
vert->setU(u+du, recipZ);
vert->setV(v, recipZ);
vert++;
vert->setScreenX(x);
vert->setScreenY(y+curfont->glyphheight);
vert->setScreenZ(rw::im2d::GetNearZ());
vert->setCameraZ(cam->nearPlane);
vert->setRecipCameraZ(recipZ);
vert->setColor(255, 255, 255, 255);
vert->setU(u, recipZ);
vert->setV(v+dv, recipZ);
vert++;
vert->setScreenX(x+curfont->glyphwidth);
vert->setScreenY(y+curfont->glyphheight);
vert->setScreenZ(rw::im2d::GetNearZ());
vert->setCameraZ(cam->nearPlane);
vert->setRecipCameraZ(recipZ);
vert->setColor(255, 255, 255, 255);
vert->setU(u+du, recipZ);
vert->setV(v+dv, recipZ);
vert++;
*ix++ = curVert;
*ix++ = curVert+1;
*ix++ = curVert+2;
*ix++ = curVert+2;
*ix++ = curVert+1;
*ix++ = curVert+3;
curVert += 4;
curIndex += 6;
x += curfont->glyphwidth+1;
s++;
}
rw::SetRenderStatePtr(rw::TEXTURERASTER, curfont->tex->raster);
rw::SetRenderState(rw::TEXTUREADDRESS, rw::Texture::WRAP);
rw::SetRenderState(rw::TEXTUREFILTER, rw::Texture::NEAREST);
im2d::RenderIndexedPrimitive(rw::PRIMTYPETRILIST,
vertices, curVert, indices, curIndex);
}
void
initFont(void)
{
vga.tex = Texture::read("Bm437_IBM_VGA8", "");
bios.tex = Texture::read("Bm437_IBM_BIOS", "");
/*
FILE *foo = fopen("font.c", "w");
assert(foo);
int x, y;
rw::Image *img = rw::readTGA("vga_font.tga");
assert(img);
for(y = 0; y < img->height; y++){
for(x = 0; x < img->width; x++)
fprintf(foo, "%d, ", !!img->pixels[y*img->width + x]);
fprintf(foo, "\n");
}
*/
}
/*
#define NUMGLYPHS 256
#define GLYPHWIDTH 8
#define GLYPHHEIGHT 16
void
convertFont(void)
{
FILE *f;
Image *img;
uint8 data[NUMGLYPHS*GLYPHHEIGHT];
int32 i, x, y;
uint8 *px, *line, *glyph;
// f = fopen("font0.bin", "rb");
f = fopen("Bm437_IBM_VGA8.FON", "rb");
// f = fopen("Bm437_IBM_BIOS.FON", "rb");
if(f == nil)
return;
fseek(f, 0x65A, 0);
fread(data, 1, NUMGLYPHS*GLYPHHEIGHT, f);
fclose(f);
img = Image::create(16*GLYPHWIDTH, NUMGLYPHS/16*GLYPHHEIGHT, 32);
img->allocate();
for(i = 0; i < NUMGLYPHS; i++){
glyph = &data[i*GLYPHHEIGHT];
x = (i % 16)*GLYPHWIDTH;
y = (i / 16)*GLYPHHEIGHT;
line = &img->pixels[x*4 + y*img->stride];
for(y = 0; y < GLYPHHEIGHT; y++){
px = line;
for(x = 0; x < 8; x++){
if(*glyph & 1<<(8-x)){
*px++ = 255;
*px++ = 255;
*px++ = 255;
*px++ = 255;
}else{
*px++ = 0;
*px++ = 0;
*px++ = 0;
*px++ = 0;
}
}
glyph++;
line += img->stride;
}
}
// writeTGA(img, "Bm437_IBM_BIOS.tga");
writeTGA(img, "Bm437_IBM_VGA8.tga");
}
*/

BIN
tools/playground/foobar.tga Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

520
tools/playground/main.cpp Normal file
View File

@@ -0,0 +1,520 @@
#include <rw.h>
#include <skeleton.h>
#include "camera.h"
#include <assert.h>
rw::V3d zero = { 0.0f, 0.0f, 0.0f };
Camera *camera;
struct SceneGlobals {
rw::World *world;
rw::Camera *camera;
rw::Clump *clump;
} Scene;
rw::Texture *tex, *tex2;
rw::Raster *testras;
rw::EngineOpenParams engineOpenParams;
rw::Texture *frontbuffer;
bool dosoftras = 0;
namespace gen {
void tlTest(rw::Clump *clump);
}
void genIm3DTransform(void *vertices, rw::int32 numVertices, rw::Matrix *xform);
void genIm3DRenderIndexed(rw::PrimitiveType prim, void *indices, rw::int32 numIndices);
void genIm3DEnd(void);
void initFont(void);
void printScreen(const char *s, float x, float y);
rw::Charset *testfont;
//#include <Windows.h>
void
Init(void)
{
// AllocConsole();
// freopen("CONIN$", "r", stdin);
// freopen("CONOUT$", "w", stdout);
// freopen("CONOUT$", "w", stderr);
sk::globals.windowtitle = "Clump viewer";
sk::globals.width = 640;
sk::globals.height = 448;
sk::globals.quit = 0;
}
bool
attachPlugins(void)
{
rw::ps2::registerPDSPlugin(40);
rw::ps2::registerPluginPDSPipes();
rw::registerMeshPlugin();
rw::registerNativeDataPlugin();
rw::registerAtomicRightsPlugin();
rw::registerMaterialRightsPlugin();
rw::xbox::registerVertexFormatPlugin();
rw::registerSkinPlugin();
rw::registerUserDataPlugin();
rw::registerHAnimPlugin();
rw::registerMatFXPlugin();
rw::registerUVAnimPlugin();
rw::ps2::registerADCPlugin();
return true;
}
void
dumpUserData(rw::UserDataArray *ar)
{
int i;
printf("name: %s\n", ar->name);
for(i = 0; i < ar->numElements; i++){
switch(ar->datatype){
case rw::USERDATAINT:
printf(" %d\n", ar->getInt(i));
break;
case rw::USERDATAFLOAT:
printf(" %f\n", ar->getFloat(i));
break;
case rw::USERDATASTRING:
printf(" %s\n", ar->getString(i));
break;
}
}
}
static rw::Frame*
dumpFrameUserDataCB(rw::Frame *f, void*)
{
using namespace rw;
int32 i;
UserDataArray *ar;
int32 n = UserDataArray::frameGetCount(f);
for(i = 0; i < n; i++){
ar = UserDataArray::frameGet(f, i);
dumpUserData(ar);
}
f->forAllChildren(dumpFrameUserDataCB, nil);
return f;
}
void
dumpUserData(rw::Clump *clump)
{
printf("Frames\n");
dumpFrameUserDataCB(clump->getFrame(), nil);
}
static rw::Frame*
getHierCB(rw::Frame *f, void *data)
{
using namespace rw;
HAnimData *hd = rw::HAnimData::get(f);
if(hd->hierarchy){
*(HAnimHierarchy**)data = hd->hierarchy;
return nil;
}
f->forAllChildren(getHierCB, data);
return f;
}
rw::HAnimHierarchy*
getHAnimHierarchyFromClump(rw::Clump *clump)
{
using namespace rw;
HAnimHierarchy *hier = nil;
getHierCB(clump->getFrame(), &hier);
return hier;
}
void
setupAtomic(rw::Atomic *atomic)
{
using namespace rw;
// just remove pipelines that we can't handle for now
// if(atomic->pipeline && atomic->pipeline->platform != rw::platform)
atomic->pipeline = NULL;
// Attach hierarchy to atomic if we're skinned
HAnimHierarchy *hier = getHAnimHierarchyFromClump(atomic->clump);
if(hier)
Skin::setHierarchy(atomic, hier);
}
static void
initHierFromFrames(rw::HAnimHierarchy *hier)
{
using namespace rw;
int32 i;
for(i = 0; i < hier->numNodes; i++){
if(hier->nodeInfo[i].frame){
hier->matrices[hier->nodeInfo[i].index] = *hier->nodeInfo[i].frame->getLTM();
}else
assert(0);
}
}
void
setupClump(rw::Clump *clump)
{
using namespace rw;
HAnimHierarchy *hier = getHAnimHierarchyFromClump(clump);
if(hier){
hier->attach();
initHierFromFrames(hier);
}
FORLIST(lnk, clump->atomics){
rw::Atomic *a = rw::Atomic::fromClump(lnk);
setupAtomic(a);
}
}
bool
InitRW(void)
{
// rw::platform = rw::PLATFORM_D3D8;
if(!sk::InitRW())
return false;
rw::d3d::isP8supported = false;
initFont();
rw::RGBA foreground = { 255, 255, 0, 255 };
rw::RGBA background = { 0, 0, 0, 0 };
rw::Charset::open();
testfont = rw::Charset::create(&foreground, &background);
assert(testfont);
foreground.blue = 255.0f;
testfont->setColors(&foreground, &background);
tex = rw::Texture::read("maze", nil);
tex2 = rw::Texture::read("checkers", nil);
const char *filename = "teapot2.dff";
if(sk::args.argc > 1)
filename = sk::args.argv[1];
rw::StreamFile in;
if(in.open(filename, "rb") == NULL){
printf("couldn't open file\n");
return false;
}
rw::findChunk(&in, rw::ID_CLUMP, NULL, NULL);
Scene.clump = rw::Clump::streamRead(&in);
assert(Scene.clump);
in.close();
// TEST - Set texture to the all materials of the clump
// FORLIST(lnk, Scene.clump->atomics){
// rw::Atomic *a = rw::Atomic::fromClump(lnk);
// for(int i = 0; i < a->geometry->matList.numMaterials; i++)
// a->geometry->matList.materials[i]->setTexture(tex);
// }
Scene.clump->getFrame()->translate(&zero, rw::COMBINEREPLACE);
dumpUserData(Scene.clump);
setupClump(Scene.clump);
Scene.world = rw::World::create();
rw::Light *ambient = rw::Light::create(rw::Light::AMBIENT);
ambient->setColor(0.3f, 0.3f, 0.3f);
Scene.world->addLight(ambient);
rw::V3d xaxis = { 1.0f, 0.0f, 0.0f };
rw::Light *direct = rw::Light::create(rw::Light::DIRECTIONAL);
direct->setColor(0.8f, 0.8f, 0.8f);
direct->setFrame(rw::Frame::create());
direct->getFrame()->rotate(&xaxis, 180.0f, rw::COMBINEREPLACE);
Scene.world->addLight(direct);
camera = new Camera;
Scene.camera = sk::CameraCreate(sk::globals.width, sk::globals.height, 1);
camera->m_rwcam = Scene.camera;
camera->m_aspectRatio = 640.0f/448.0f;
camera->m_near = 5.0f;
// camera->m_far = 450.0f;
camera->m_far = 15.0f;
camera->m_target.set(0.0f, 0.0f, 0.0f);
camera->m_position.set(0.0f, -10.0f, 0.0f);
// camera->setPosition(Vec3(0.0f, 5.0f, 0.0f));
// camera->setPosition(Vec3(0.0f, -70.0f, 0.0f));
// camera->setPosition(Vec3(0.0f, -1.0f, 3.0f));
camera->update();
Scene.world->addCamera(camera->m_rwcam);
return true;
}
void
im2dtest(void)
{
using namespace rw::RWDEVICE;
int i;
static struct
{
float x, y;
rw::uint8 r, g, b, a;
float u, v;
} vs[4] = {
{ 0.0f, 0.0f, 255, 0, 0, 128, 0.0f, 0.0f },
{ 640.0f, 0.0f, 0, 255, 0, 128, 1.0f, 0.0f },
{ 0.0f, 448.0f, 0, 0, 255, 128, 0.0f, 1.0f },
{ 640.0f, 448.0f, 0, 255, 255, 128, 1.0f, 1.0f },
/*
{ 0.0f, 0.0f, 255, 0, 0, 128, 0.0f, 1.0f },
{ 640.0f, 0.0f, 0, 255, 0, 128, 0.0f, 0.0f },
{ 0.0f, 448.0f, 0, 0, 255, 128, 1.0f, 1.0f },
{ 640.0f, 448.0f, 0, 255, 255, 128, 1.0f, 0.0f },
*/
};
Im2DVertex verts[4];
static short indices[] = {
0, 1, 2, 3
};
float recipZ = 1.0f/Scene.camera->nearPlane;
for(i = 0; i < 4; i++){
verts[i].setScreenX(vs[i].x);
verts[i].setScreenY(vs[i].y);
verts[i].setScreenZ(rw::im2d::GetNearZ());
verts[i].setCameraZ(Scene.camera->nearPlane);
verts[i].setRecipCameraZ(recipZ);
verts[i].setColor(vs[i].r, vs[i].g, vs[i].b, vs[i].a);
if(dosoftras)
verts[i].setColor(255, 255, 255, 255);
verts[i].setU(vs[i].u + 0.5f/640.0f, recipZ);
verts[i].setV(vs[i].v + 0.5f/448.0f, recipZ);
}
rw::SetRenderStatePtr(rw::TEXTURERASTER, tex->raster);
if(dosoftras)
rw::SetRenderStatePtr(rw::TEXTURERASTER, testras);
rw::SetRenderState(rw::TEXTUREADDRESS, rw::Texture::WRAP);
rw::SetRenderState(rw::TEXTUREFILTER, rw::Texture::NEAREST);
rw::SetRenderState(rw::VERTEXALPHA, 1);
rw::im2d::RenderIndexedPrimitive(rw::PRIMTYPETRISTRIP,
&verts, 4, &indices, 4);
}
void
im3dtest(void)
{
using namespace rw::RWDEVICE;
int i;
static struct
{
float x, y, z;
rw::uint8 r, g, b, a;
float u, v;
} vs[8] = {
{ -1.0f, -1.0f, -1.0f, 255, 0, 0, 128, 0.0f, 0.0f },
{ -1.0f, 1.0f, -1.0f, 0, 255, 0, 128, 0.0f, 1.0f },
{ 1.0f, -1.0f, -1.0f, 0, 0, 255, 128, 1.0f, 0.0f },
{ 1.0f, 1.0f, -1.0f, 255, 0, 255, 128, 1.0f, 1.0f },
{ -1.0f, -1.0f, 1.0f, 255, 0, 0, 128, 0.0f, 0.0f },
{ -1.0f, 1.0f, 1.0f, 0, 255, 0, 128, 0.0f, 1.0f },
{ 1.0f, -1.0f, 1.0f, 0, 0, 255, 128, 1.0f, 0.0f },
{ 1.0f, 1.0f, 1.0f, 255, 0, 255, 128, 1.0f, 1.0f },
};
Im3DVertex verts[8];
static short indices[2*6] = {
0, 1, 2, 2, 1, 3,
4, 5, 6, 6, 5, 7
};
for(i = 0; i < 8; i++){
verts[i].setX(vs[i].x);
verts[i].setY(vs[i].y);
verts[i].setZ(vs[i].z);
verts[i].setColor(vs[i].r, vs[i].g, vs[i].b, vs[i].a);
verts[i].setU(vs[i].u);
verts[i].setV(vs[i].v);
}
// rw::SetRenderStatePtr(rw::TEXTURERASTER, tex->raster);
rw::SetRenderStatePtr(rw::TEXTURERASTER, testfont->raster);
// rw::SetRenderStatePtr(rw::TEXTURERASTER, frontbuffer->raster);
rw::SetRenderState(rw::TEXTUREADDRESS, rw::Texture::WRAP);
rw::SetRenderState(rw::TEXTUREFILTER, rw::Texture::NEAREST);
/*
genIm3DTransform(verts, 8, nil);
genIm3DRenderIndexed(rw::PRIMTYPETRILIST, indices, 12);
genIm3DEnd();
*/
rw::im3d::Transform(verts, 8, nil);
rw::im3d::RenderIndexedPrimitive(rw::PRIMTYPETRILIST, indices, 12);
rw::im3d::End();
}
void
getFrontBuffer(void)
{
rw::Raster *fb = Scene.camera->frameBuffer;
if(frontbuffer == nil || fb->width > frontbuffer->raster->width || fb->height > frontbuffer->raster->height){
int w, h;
for(w = 1; w < fb->width; w <<= 1);
for(h = 1; h < fb->height; h <<= 1);
rw::Raster *ras = rw::Raster::create(w, h, fb->depth, rw::Raster::CAMERATEXTURE);
if(frontbuffer){
frontbuffer->raster->destroy();
frontbuffer->raster = ras;
}else
frontbuffer = rw::Texture::create(ras);
printf("created FB with %d %d %d\n", ras->width, ras->height, ras->depth);
}
rw::Raster::pushContext(frontbuffer->raster);
fb->renderFast(0, 0);
rw::Raster::popContext();
}
void
Draw(float timeDelta)
{
getFrontBuffer();
static rw::RGBA clearcol = { 0x60, 0x60, 0x60, 0xFF };
camera->m_rwcam->clear(&clearcol, rw::Camera::CLEARIMAGE|rw::Camera::CLEARZ);
camera->update();
camera->m_rwcam->beginUpdate();
extern void beginSoftras(void);
beginSoftras();
// gen::tlTest(Scene.clump);
void drawtest(void);
// drawtest();
extern void endSoftras(void);
if(dosoftras){
endSoftras();
}
// im2dtest();
// Scene.clump->render();
im3dtest();
// printScreen("Hello, World!", 10, 10);
testfont->print("foo ABC", 200, 200, true);
camera->m_rwcam->endUpdate();
camera->m_rwcam->showRaster();
}
void
KeyUp(int key)
{
}
void
KeyDown(int key)
{
switch(key){
case 'W':
camera->orbit(0.0f, 0.1f);
break;
case 'S':
camera->orbit(0.0f, -0.1f);
break;
case 'A':
camera->orbit(-0.1f, 0.0f);
break;
case 'D':
camera->orbit(0.1f, 0.0f);
break;
case sk::KEY_UP:
camera->turn(0.0f, 0.1f);
break;
case sk::KEY_DOWN:
camera->turn(0.0f, -0.1f);
break;
case sk::KEY_LEFT:
camera->turn(0.1f, 0.0f);
break;
case sk::KEY_RIGHT:
camera->turn(-0.1f, 0.0f);
break;
case 'R':
camera->zoom(0.1f);
break;
case 'F':
camera->zoom(-0.1f);
break;
case 'V':
dosoftras = !dosoftras;
break;
case sk::KEY_ESC:
sk::globals.quit = 1;
break;
}
}
void
MouseMove(int x, int y)
{
}
void
MouseButton(int buttons)
{
}
sk::EventStatus
AppEventHandler(sk::Event e, void *param)
{
using namespace sk;
Rect *r;
MouseState *ms;
switch(e){
case INITIALIZE:
Init();
return EVENTPROCESSED;
case RWINITIALIZE:
return ::InitRW() ? EVENTPROCESSED : EVENTERROR;
case PLUGINATTACH:
return attachPlugins() ? EVENTPROCESSED : EVENTERROR;
case KEYDOWN:
KeyDown(*(int*)param);
return EVENTPROCESSED;
case KEYUP:
KeyUp(*(int*)param);
return EVENTPROCESSED;
case MOUSEBTN:
ms = (MouseState*)param;
MouseButton(ms->buttons);
return EVENTPROCESSED;
case MOUSEMOVE:
ms = (MouseState*)param;
MouseMove(ms->posx, ms->posy);
return EVENTPROCESSED;
case RESIZE:
r = (Rect*)param;
// TODO: register when we're minimized
if(r->w == 0) r->w = 1;
if(r->h == 0) r->h = 1;
sk::globals.width = r->w;
sk::globals.height = r->h;
if(camera)
camera->m_aspectRatio = (float)r->w/r->h;
if(Scene.camera)
sk::CameraSize(Scene.camera, r);
break;
case IDLE:
Draw(*(float*)param);
return EVENTPROCESSED;
}
return sk::EVENTNOTPROCESSED;
}

BIN
tools/playground/maze.tga Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -0,0 +1,902 @@
#include <rw.h>
#include <skeleton.h>
namespace rs {
typedef int8_t i8;
typedef uint8_t u8;
typedef int16_t i16;
typedef uint16_t u16;
typedef int32_t i32;
typedef uint32_t u32;
typedef int64_t i64;
typedef uint64_t u64;
typedef struct Canvas Canvas;
struct Canvas
{
u8 *fb;
u32 *zbuf;
int w, h;
};
extern Canvas *canvas;
typedef struct Texture Texture;
struct Texture
{
u8 *pixels;
int w, h;
int wrap;
};
typedef struct Point3 Point3;
struct Point3
{
int x, y, z;
};
typedef struct Color Color;
struct Color
{
u8 r, g, b, a;
};
typedef struct Vertex Vertex;
struct Vertex
{
i32 x, y, z;
float q; // 1/z
u8 r, g, b, a;
u8 f; // fog
float s, t;
};
Canvas *makecanvas(int w, int h);
Texture *maketexture(int w, int h);
void putpixel(Canvas *canvas, Point3 p, Color c);
void clearcanvas(Canvas *canvas);
void drawTriangle(Canvas *canvas, Vertex p1, Vertex p2, Vertex p3);
// not good
void drawRect(Canvas *canvas, Point3 p1, Point3 p2, Color c);
void drawLine(Canvas *canvas, Point3 p1, Point3 p2, Color c);
//#define trace(...) printf(__VA_ARGS__)
#define trace(...)
int clamp(int x);
/*
* Render States
*/
enum TextureWrap {
WRAP_REPEAT,
WRAP_CLAMP,
WRAP_BORDER,
};
enum TextureFunction {
TFUNC_MODULATE,
TFUNC_DECAL,
TFUNC_HIGHLIGHT,
TFUNC_HIGHLIGHT2,
};
enum AlphaTestFunc {
ALPHATEST_NEVER,
ALPHATEST_ALWAYS,
ALPHATEST_LESS,
ALPHATEST_LEQUAL,
ALPHATEST_EQUAL,
ALPHATEST_GEQUAL,
ALPHATEST_GREATER,
ALPHATEST_NOTEQUAL,
};
enum AlphaTestFail {
ALPHAFAIL_KEEP,
ALPHAFAIL_FB_ONLY,
ALPHAFAIL_ZB_ONLY,
};
enum DepthTestFunc {
DEPTHTEST_NEVER,
DEPTHTEST_ALWAYS,
DEPTHTEST_GEQUAL,
DEPTHTEST_GREATER,
};
// The blend equation is
// out = ((A - B) * C >> 7) + D
// A, B and D select the color, C the alpha value
enum AlphaBlendOp {
ALPHABLEND_SRC,
ALPHABLEND_DST,
ALPHABLEND_ZERO,
ALPHABLEND_FIX = ALPHABLEND_ZERO,
};
extern int srScissorX0, srScissorX1;
extern int srScissorY0, srScissorY1;
extern int srDepthTestEnable;
extern int srDepthTestFunction;
extern int srWriteZ;
extern int srAlphaTestEnable;
extern int srAlphaTestFunction;
extern int srAlphaTestReference;
extern int srAlphaTestFail;
extern int srAlphaBlendEnable;
extern int srAlphaBlendA;
extern int srAlphaBlendB;
extern int srAlphaBlendC;
extern int srAlphaBlendD;
extern int srAlphaBlendFix;
extern int srTexEnable;
extern Texture *srTexture;
extern int srWrapU;
extern int srWrapV;
extern Color srBorder;
extern int srTexUseAlpha;
extern int srTexFunc;
extern int srFogEnable;
extern Color srFogCol;
// end header
#define CEIL(p) (((p)+15) >> 4)
// render states
int srScissorX0, srScissorX1;
int srScissorY0, srScissorY1;
int srDepthTestEnable = 1;
int srDepthTestFunction = DEPTHTEST_GEQUAL;
int srWriteZ = 1;
int srAlphaTestEnable = 1;
int srAlphaTestFunction = ALPHATEST_ALWAYS;
int srAlphaTestReference;
int srAlphaTestFail = ALPHAFAIL_FB_ONLY;
int srAlphaBlendEnable = 1;
int srAlphaBlendA = ALPHABLEND_SRC;
int srAlphaBlendB = ALPHABLEND_DST;
int srAlphaBlendC = ALPHABLEND_SRC;
int srAlphaBlendD = ALPHABLEND_DST;
int srAlphaBlendFix = 0x80;
int srTexEnable = 0;
Texture *srTexture;
int srWrapU = WRAP_REPEAT;
int srWrapV = WRAP_REPEAT;
Color srBorder = { 255, 0, 0, 255 };
int srTexUseAlpha = 1;
int srTexFunc = TFUNC_MODULATE;
int srFogEnable = 0;
Color srFogCol = { 0, 0, 0, 0 };
int clamp(int x) { if(x < 0) return 0; if(x > 255) return 255; return x; }
Canvas*
makecanvas(int w, int h)
{
Canvas *canv;
canv = (Canvas*)malloc(sizeof(*canv) + w*h*(4+4));
canv->w = w;
canv->h = h;
canv->fb = ((u8*)canv + sizeof(*canv));
canv->zbuf = (u32*)(canv->fb + w*h*4);
return canv;
}
Texture*
maketexture(int w, int h)
{
Texture *t;
t = (Texture*)malloc(sizeof(*t) + w*h*4);
t->w = w;
t->h = h;
t->pixels = (u8*)t + sizeof(*t);
t->wrap = 0x11; // wrap u and v
return t;
}
void
clearcanvas(Canvas *canvas)
{
memset(canvas->fb, 0, canvas->w*canvas->h*4);
memset(canvas->zbuf, 0, canvas->w*canvas->h*4);
}
void
writefb(Canvas *canvas, int x, int y, Color c)
{
u8 *px = &canvas->fb[(y*canvas->w + x)*4];
u32 *z = &canvas->zbuf[y*canvas->w + x];
px[3] = c.r;
px[2] = c.g;
px[1] = c.b;
px[0] = c.a;
}
void
putpixel(Canvas *canvas, Point3 p, Color c)
{
// scissor test
if(p.x < srScissorX0 || p.x > srScissorX1 ||
p.y < srScissorY0 || p.y > srScissorY1)
return;
u8 *px = &canvas->fb[(p.y*canvas->w + p.x)*4];
u32 *z = &canvas->zbuf[p.y*canvas->w + p.x];
int fbwrite = 1;
int zbwrite = srWriteZ;
// alpha test
if(srAlphaTestEnable){
int fail;
switch(srAlphaTestFunction){
case ALPHATEST_NEVER:
fail = 1;
break;
case ALPHATEST_ALWAYS:
fail = 0;
break;
case ALPHATEST_LESS:
fail = c.a >= srAlphaTestReference;
break;
case ALPHATEST_LEQUAL:
fail = c.a > srAlphaTestReference;
break;
case ALPHATEST_EQUAL:
fail = c.a != srAlphaTestReference;
break;
case ALPHATEST_GEQUAL:
fail = c.a < srAlphaTestReference;
break;
case ALPHATEST_GREATER:
fail = c.a <= srAlphaTestReference;
break;
case ALPHATEST_NOTEQUAL:
fail = c.a == srAlphaTestReference;
break;
}
if(fail){
switch(srAlphaTestFail){
case ALPHAFAIL_KEEP:
return;
case ALPHAFAIL_FB_ONLY:
zbwrite = 0;
break;
case ALPHAFAIL_ZB_ONLY:
fbwrite = 0;
}
}
}
// ztest
if(srDepthTestEnable){
switch(srDepthTestFunction){
case DEPTHTEST_NEVER:
return;
case DEPTHTEST_ALWAYS:
break;
case DEPTHTEST_GEQUAL:
if((u32)p.z < *z)
return;
break;
case DEPTHTEST_GREATER:
if((u32)p.z <= *z)
return;
break;
}
}
Color d = { px[3], px[2], px[1], px[0] };
// blend
if(srAlphaBlendEnable){
int ar, ag, ab;
int br, bg, bb;
int dr, dg, db;
int ca;
switch(srAlphaBlendA){
case ALPHABLEND_SRC:
ar = c.r;
ag = c.g;
ab = c.b;
break;
case ALPHABLEND_DST:
ar = d.r;
ag = d.g;
ab = d.b;
break;
case ALPHABLEND_ZERO:
ar = 0;
ag = 0;
ab = 0;
break;
default: assert(0);
}
switch(srAlphaBlendB){
case ALPHABLEND_SRC:
br = c.r;
bg = c.g;
bb = c.b;
break;
case ALPHABLEND_DST:
br = d.r;
bg = d.g;
bb = d.b;
break;
case ALPHABLEND_ZERO:
br = 0;
bg = 0;
bb = 0;
break;
default: assert(0);
}
switch(srAlphaBlendC){
case ALPHABLEND_SRC:
ca = c.a;
break;
case ALPHABLEND_DST:
ca = d.a;
break;
case ALPHABLEND_FIX:
ca = srAlphaBlendFix;
break;
default: assert(0);
}
switch(srAlphaBlendD){
case ALPHABLEND_SRC:
dr = c.r;
dg = c.g;
db = c.b;
break;
case ALPHABLEND_DST:
dr = d.r;
dg = d.g;
db = d.b;
break;
case ALPHABLEND_ZERO:
dr = 0;
dg = 0;
db = 0;
break;
default: assert(0);
}
int r, g, b;
r = ((ar - br) * ca >> 7) + dr;
g = ((ag - bg) * ca >> 7) + dg;
b = ((ab - bb) * ca >> 7) + db;
c.r = clamp(r);
c.g = clamp(g);
c.b = clamp(b);
}
if(fbwrite)
writefb(canvas, p.x, p.y, c);
if(zbwrite)
*z = p.z;
}
Color
sampletex_nearest(int u, int v)
{
Texture *tex = srTexture;
const int usize = tex->w;
const int vsize = tex->h;
int iu = u >> 4;
int iv = v >> 4;
switch(srWrapU){
case WRAP_REPEAT:
iu %= usize;
break;
case WRAP_CLAMP:
if(iu < 0) iu = 0;
if(iu >= usize) iu = usize-1;
break;
case WRAP_BORDER:
if(iu < 0 || iu >= usize)
return srBorder;
}
switch(srWrapV){
case WRAP_REPEAT:
iv %= vsize;
break;
case WRAP_CLAMP:
if(iv < 0) iv = 0;
if(iv >= vsize) iv = vsize-1;
break;
case WRAP_BORDER:
if(iv < 0 || iv >= vsize)
return srBorder;
}
u8 *cp = &tex->pixels[(iv*tex->w + iu)*4];
Color c = { cp[0], cp[1], cp[2], cp[3] };
return c;
}
// t is texture, f is fragment
Color
texfunc(Color t, Color f)
{
int r, g, b, a;
switch(srTexFunc){
case TFUNC_MODULATE:
r = t.r * f.r >> 7;
g = t.g * f.g >> 7;
b = t.b * f.b >> 7;
a = srTexUseAlpha ?
t.a * f.a >> 7 :
f.a;
break;
case TFUNC_DECAL:
r = t.r;
g = t.g;
b = t.b;
a = srTexUseAlpha ? t.a : f.a;
break;
case TFUNC_HIGHLIGHT:
r = (t.r * f.r >> 7) + f.a;
g = (t.g * f.g >> 7) + f.a;
b = (t.b * f.b >> 7) + f.a;
a = srTexUseAlpha ?
t.a + f.a :
f.a;
break;
case TFUNC_HIGHLIGHT2:
r = (t.r * f.r >> 7) + f.a;
g = (t.g * f.g >> 7) + f.a;
b = (t.b * f.b >> 7) + f.a;
a = srTexUseAlpha ? t.a : f.a;
break;
}
Color v;
v.r = clamp(r);
v.g = clamp(g);
v.b = clamp(b);
v.a = clamp(a);
return v;
}
Point3 mkpnt(int x, int y, int z) { Point3 p = { x, y, z}; return p; }
void
drawRect(Canvas *canvas, Point3 p1, Point3 p2, Color c)
{
int x, y;
for(y = p1.y; y <= p2.y; y++)
for(x = p1.x; x <= p2.x; x++)
putpixel(canvas, mkpnt(x, y, 0), c);
}
void
drawLine(Canvas *canvas, Point3 p1, Point3 p2, Color c)
{
int dx, dy;
int incx, incy;
int e;
int x, y;
dx = abs(p2.x-p1.x);
incx = p2.x > p1.x ? 1 : -1;
dy = abs(p2.y-p1.y);
incy = p2.y > p1.y ? 1 : -1;
e = 0;
if(dx == 0){
for(y = p1.y; y != p2.y; y += incy)
putpixel(canvas, mkpnt(p1.x, y, 0), c);
}else if(dx > dy){
y = p1.y;
for(x = p1.x; x != p2.x; x += incx){
putpixel(canvas, mkpnt(x, y, 0), c);
e += dy;
if(2*e >= dx){
e -= dx;
y += incy;
}
}
}else{
x = p1.x;
for(y = p1.y; y != p2.y; y += incy){
putpixel(canvas, mkpnt(x, y, 0), c);
e += dx;
if(2*e >= dy){
e -= dy;
x += incx;
}
}
}
}
/*
attibutes we want to interpolate:
R G B A
U V / S T Q
X Y Z F
*/
struct TriAttribs
{
i64 z;
i32 r, g, b, a;
i32 f;
float s, t;
float q;
};
static void
add1(struct TriAttribs *a, struct TriAttribs *b)
{
a->z += b->z;
a->r += b->r;
a->g += b->g;
a->b += b->b;
a->a += b->a;
a->f += b->f;
a->s += b->s;
a->t += b->t;
a->q += b->q;
}
static void
sub1(struct TriAttribs *a, struct TriAttribs *b)
{
a->z -= b->z;
a->r -= b->r;
a->g -= b->g;
a->b -= b->b;
a->a -= b->a;
a->f -= b->f;
a->s -= b->s;
a->t -= b->t;
a->q -= b->q;
}
static void
guard(struct TriAttribs *a)
{
if(a->z < 0) a->z = 0;
else if(a->z > 0x3FFFFFFFC000LL) a->z = 0x3FFFFFFFC000LL;
if(a->r < 0) a->r = 0;
else if(a->r > 0xFF000) a->r = 0xFF000;
if(a->g < 0) a->g = 0;
else if(a->g > 0xFF000) a->g = 0xFF000;
if(a->b < 0) a->b = 0;
else if(a->b > 0xFF000) a->b = 0xFF000;
if(a->a < 0) a->a = 0;
else if(a->a > 0xFF000) a->a = 0xFF000;
if(a->f < 0) a->f = 0;
else if(a->f > 0xFF000) a->f = 0xFF000;
}
struct RasTri
{
int x, y;
int ymid, yend;
int right;
int e[2], dx[3], dy[3];
struct TriAttribs gx, gy, v, s;
};
static int
triangleSetup(struct RasTri *tri, Vertex v1, Vertex v2, Vertex v3)
{
int dx1, dx2, dx3;
int dy1, dy2, dy3;
dy1 = v3.y - v1.y; // long edge
if(dy1 == 0) return 1;
dx1 = v3.x - v1.x;
dx2 = v2.x - v1.x; // first small edge
dy2 = v2.y - v1.y;
dx3 = v3.x - v2.x; // second small edge
dy3 = v3.y - v2.y;
// this is twice the triangle area
const int area = dx2*dy1 - dx1*dy2;
if(area == 0) return 1;
// figure out if 0 or 1 is the right edge
tri->right = area < 0;
/* The gradients are to step whole pixels,
* so they are pre-multiplied by 16. */
float denom = 16.0f/area;
// gradients x
#define GX(p) ((v2.p - v1.p)*dy1 - (v3.p - v1.p)*dy2)
tri->gx.z = GX(z)*denom * 16384;
tri->gx.r = GX(r)*denom * 4096;
tri->gx.g = GX(g)*denom * 4096;
tri->gx.b = GX(b)*denom * 4096;
tri->gx.a = GX(a)*denom * 4096;
tri->gx.f = GX(f)*denom * 4096;
tri->gx.s = GX(s)*denom;
tri->gx.t = GX(t)*denom;
tri->gx.q = GX(q)*denom;
// gradients y
denom = -denom;
#define GY(p) ((v2.p - v1.p)*dx1 - (v3.p - v1.p)*dx2)
tri->gy.z = GY(z)*denom * 16384;
tri->gy.r = GY(r)*denom * 4096;
tri->gy.g = GY(g)*denom * 4096;
tri->gy.b = GY(b)*denom * 4096;
tri->gy.a = GY(a)*denom * 4096;
tri->gy.f = GY(f)*denom * 4096;
tri->gy.s = GY(s)*denom;
tri->gy.t = GY(t)*denom;
tri->gy.q = GY(q)*denom;
tri->ymid = CEIL(v2.y);
tri->yend = CEIL(v3.y);
tri->y = CEIL(v1.y);
tri->x = CEIL(v1.x);
tri->dy[0] = dy2<<4; // upper edge
tri->dy[1] = dy1<<4; // lower edge
tri->dy[2] = dy3<<4; // long edge
tri->dx[0] = dx2<<4;
tri->dx[1] = dx1<<4;
tri->dx[2] = dx3<<4;
// prestep to land on pixel center
int stepx = v1.x - (tri->x<<4);
int stepy = v1.y - (tri->y<<4);
tri->e[0] = (-stepy*tri->dx[0] + stepx*tri->dy[0]) >> 4;
tri->e[1] = (-stepy*tri->dx[1] + stepx*tri->dy[1]) >> 4;
// attributes along interpolated edge
// why is this cast needed? (mingw)
tri->v.z = (i64)v1.z*16384 - (stepy*tri->gy.z + stepx*tri->gx.z)/16;
tri->v.r = v1.r*4096 - (stepy*tri->gy.r + stepx*tri->gx.r)/16;
tri->v.g = v1.g*4096 - (stepy*tri->gy.g + stepx*tri->gx.g)/16;
tri->v.b = v1.b*4096 - (stepy*tri->gy.b + stepx*tri->gx.b)/16;
tri->v.a = v1.a*4096 - (stepy*tri->gy.a + stepx*tri->gx.a)/16;
tri->v.f = v1.f*4096 - (stepy*tri->gy.f + stepx*tri->gx.f)/16;
tri->v.s = v1.s - (stepy*tri->gy.s + stepx*tri->gx.s)/16.0f;
tri->v.t = v1.t - (stepy*tri->gy.t + stepx*tri->gx.t)/16.0f;
tri->v.q = v1.q - (stepy*tri->gy.q + stepx*tri->gx.q)/16.0f;
return 0;
}
void
drawTriangle(Canvas *canvas, Vertex v1, Vertex v2, Vertex v3)
{
Color c;
struct RasTri tri;
int stepx, stepy;
// Sort such that we have from top to bottom v1,v2,v3
if(v2.y < v1.y){ Vertex tmp = v1; v1 = v2; v2 = tmp; }
if(v3.y < v1.y){ Vertex tmp = v1; v1 = v3; v3 = tmp; }
if(v3.y < v2.y){ Vertex tmp = v2; v2 = v3; v3 = tmp; }
if(triangleSetup(&tri, v1, v2, v3))
return;
// Current scanline start and end
int xn[2] = { tri.x, tri.x };
int a = !tri.right; // left edge
int b = tri.right; // right edge
// If upper triangle has no height, only do the lower part
if(tri.dy[0] == 0)
goto secondtri;
while(tri.y < tri.yend){
/* TODO: is this the righ way to step the edges? */
/* Step x and interpolated value down left edge */
while(tri.e[a] <= -tri.dy[a]){
xn[a]--;
tri.e[a] += tri.dy[a];
sub1(&tri.v, &tri.gx);
}
while(tri.e[a] > 0){
xn[a]++;
tri.e[a] -= tri.dy[a];
add1(&tri.v, &tri.gx);
}
/* Step x down right edge */
while(tri.e[b] <= -tri.dy[b]){
xn[b]--;
tri.e[b] += tri.dy[b];
}
while(tri.e[b] > 0){
xn[b]++;
tri.e[b] -= tri.dy[b];
}
// When we reach the mid vertex, change state and jump to start of loop again
// TODO: this is a bit ugly in here...can we fix it?
if(tri.y == tri.ymid){
secondtri:
tri.dx[0] = tri.dx[2];
tri.dy[0] = tri.dy[2];
// Either the while prevents this or we returned early because dy1 == 0
assert(tri.dy[0] != 0);
stepx = v2.x - (xn[0]<<4);
stepy = v2.y - (tri.y<<4);
tri.e[0] = (-stepy*tri.dx[0] + stepx*tri.dy[0]) >> 4;
tri.ymid = -1; // so we don't do this again
continue;
}
/* Rasterize one line */
tri.s = tri.v;
for(tri.x = xn[a]; tri.x < xn[b]; tri.x++){
guard(&tri.s);
c.r = tri.s.r >> 12;
c.g = tri.s.g >> 12;
c.b = tri.s.b >> 12;
c.a = tri.s.a >> 12;
if(srTexEnable && srTexture){
float w = 1.0f/tri.s.q;
float s = tri.s.s * w;
float t = tri.s.t * w;
int u = s * srTexture->w * 16;
int v = t * srTexture->h * 16;
Color texc = sampletex_nearest(u, v);
c = texfunc(texc, c);
}
if(srFogEnable){
const int f = tri.s.f >> 12;
c.r = (f*c.r >> 8) + ((255 - f)*srFogCol.r >> 8);
c.g = (f*c.g >> 8) + ((255 - f)*srFogCol.g >> 8);
c.b = (f*c.b >> 8) + ((255 - f)*srFogCol.b >> 8);
}
putpixel(canvas, mkpnt(tri.x, tri.y, tri.s.z>>14), c);
add1(&tri.s, &tri.gx);
}
/* Step in y */
tri.y++;
tri.e[a] += tri.dx[a];
tri.e[b] += tri.dx[b];
add1(&tri.v, &tri.gy);
}
}
Canvas *canvas;
}
using namespace rw;
void
rastest_renderTriangles(RWDEVICE::Im2DVertex *scrverts, int32 numVerts, uint16 *indices, int32 numTris)
{
int i;
RGBA col;
rs::Vertex v[3];
RWDEVICE::Im2DVertex *iv;
rs::srDepthTestEnable = 1;
rs::srAlphaTestEnable = 0;
rs::srTexEnable = 0;
rs::srAlphaBlendEnable = 0;
while(numTris--){
for(i = 0; i < 3; i++){
iv = &scrverts[indices[i]];
v[i].x = iv->x * 16.0f;
v[i].y = iv->y * 16.0f;
v[i].z = 16777216*(1.0f-iv->z);
v[i].q = iv->w;
col = iv->getColor();
v[i].r = col.red;
v[i].g = col.green;
v[i].b = col.blue;
v[i].a = col.alpha;
v[i].f = 0;
v[i].s = iv->u*iv->w;
v[i].t = iv->v*iv->w;
}
drawTriangle(rs::canvas, v[0], v[1], v[2]);
indices += 3;
}
}
extern rw::Raster *testras;
void
beginSoftras(void)
{
Camera *cam = (Camera*)engine->currentCamera;
if(rs::canvas == nil ||
cam->frameBuffer->width != rs::canvas->w ||
cam->frameBuffer->height != rs::canvas->h){
rs::canvas = rs::makecanvas(cam->frameBuffer->width, cam->frameBuffer->height);
testras = rw::Raster::create(rs::canvas->w, rs::canvas->h, 32, rw::Raster::C8888);
}
clearcanvas(rs::canvas);
rs::srScissorX0 = 0;
rs::srScissorX1 = rs::canvas->w-1;
rs::srScissorY0 = 0;
rs::srScissorY1 = rs::canvas->h-1;
}
void
endSoftras(void)
{
int i;
uint8 *dst = testras->lock(0, Raster::LOCKWRITE|Raster::LOCKNOFETCH);
if(dst == nil)
return;
uint8 *src = rs::canvas->fb;
for(i = 0; i < rs::canvas->w*rs::canvas->h; i++){
dst[0] = src[1];
dst[1] = src[2];
dst[2] = src[3];
dst[3] = src[0];
dst += 4;
src += 4;
}
// abgr in canvas
// bgra in raster
testras->unlock(0);
}
/*
typedef struct PixVert PixVert;
struct PixVert
{
float x, y, z, q;
int r, g, b, a;
float u, v;
};
#include "test.inc"
void
drawtest(void)
{
int i, j;
rs::Vertex v[3];
rs::srDepthTestEnable = 1;
rs::srAlphaTestEnable = 0;
rs::srTexEnable = 0;
rs::srAlphaBlendEnable = 0;
for(i = 0; i < nelem(verts); i += 3){
for(j = 0; j < 3; j++){
v[j].x = verts[i+j].x * 16.0f;
v[j].y = verts[i+j].y * 16.0f;
v[j].z = 16777216*(1.0f - verts[i+j].z);
v[j].q = verts[i+j].q;
v[j].r = verts[i+j].r;
v[j].g = verts[i+j].g;
v[j].b = verts[i+j].b;
v[j].a = verts[i+j].a;
v[j].f = 0;
v[j].s = verts[i+j].u*v[j].q;
v[j].t = verts[i+j].v*v[j].q;
}
drawTriangle(rs::canvas, v[0], v[1], v[2]);
}
//exit(0);
}
*/

BIN
tools/playground/teapot.dff Normal file

Binary file not shown.

View File

@@ -0,0 +1,662 @@
#include <rw.h>
#include <skeleton.h>
extern bool dosoftras;
using namespace rw;
using namespace RWDEVICE;
void rastest_renderTriangles(RWDEVICE::Im2DVertex *scrverts, int32 verts, uint16 *indices, int32 numTris);
//
// This is a test to implement T&L in software and render with Im2D
//
namespace gen {
#define MAX_LIGHTS 8
struct Directional {
V3d at;
RGBAf color;
};
static Directional directionals[MAX_LIGHTS];
static int32 numDirectionals;
static RGBAf ambLight;
static void
enumLights(Matrix *lightmat)
{
int32 n;
World *world;
world = (World*)engine->currentWorld;
ambLight.red = 0.0;
ambLight.green = 0.0;
ambLight.blue = 0.0;
ambLight.alpha = 0.0;
numDirectionals = 0;
// only unpositioned lights right now
FORLIST(lnk, world->globalLights){
Light *l = Light::fromWorld(lnk);
if(l->getType() == Light::DIRECTIONAL){
if(numDirectionals >= MAX_LIGHTS)
continue;
n = numDirectionals++;
V3d::transformVectors(&directionals[n].at, &l->getFrame()->getLTM()->at, 1, lightmat);
directionals[n].color = l->color;
directionals[n].color.alpha = 0.0f;
}else if(l->getType() == Light::AMBIENT){
ambLight.red += l->color.red;
ambLight.green += l->color.green;
ambLight.blue += l->color.blue;
}
}
}
struct ObjSpace3DVertex
{
V3d objVertex;
V3d objNormal;
RGBA color;
TexCoords texCoords;
};
enum {
CLIPXLO = 0x01,
CLIPXHI = 0x02,
CLIPX = 0x03,
CLIPYLO = 0x04,
CLIPYHI = 0x08,
CLIPY = 0x0C,
CLIPZLO = 0x10,
CLIPZHI = 0x20,
CLIPZ = 0x30,
};
struct CamSpace3DVertex
{
V3d camVertex;
uint8 clipFlags;
RGBAf color;
TexCoords texCoords;
};
struct InstanceData
{
uint16 *indices;
int32 numIndices;
ObjSpace3DVertex *vertices;
int32 numVertices;
// int vertStride; // not really needed right now
Material *material;
Mesh *mesh;
};
struct InstanceDataHeader : public rw::InstanceDataHeader
{
uint32 serialNumber;
ObjSpace3DVertex *vertices;
uint16 *indices;
InstanceData *inst;
};
static void
instanceAtomic(Atomic *atomic)
{
static V3d zeroNorm = { 0.0f, 0.0f, 0.0f };
static RGBA black = { 0, 0, 0, 255 };
static TexCoords zeroTex = { 0.0f, 0.0f };
int i;
uint j;
int x, x1, x2, x3;
Geometry *geo;
MeshHeader *header;
Mesh *mesh;
InstanceDataHeader *insthead;
InstanceData *inst;
uint32 firstVert;
uint16 *srcindices, *dstindices;
geo = atomic->geometry;
if(geo->instData)
return;
header = geo->meshHeader;
int numTris;
if(header->flags & MeshHeader::TRISTRIP)
numTris = header->totalIndices - 2*header->numMeshes;
else
numTris = header->totalIndices / 3;
int size;
size = sizeof(InstanceDataHeader) + header->numMeshes*sizeof(InstanceData) +
geo->numVertices*sizeof(ObjSpace3DVertex) + numTris*6*sizeof(uint16);
insthead = (InstanceDataHeader*)rwNew(size, ID_GEOMETRY);
geo->instData = insthead;
insthead->platform = 0;
insthead->serialNumber = header->serialNum;
inst = (InstanceData*)(insthead+1);
insthead->inst = inst;
insthead->vertices = (ObjSpace3DVertex*)(inst+header->numMeshes);
dstindices = (uint16*)(insthead->vertices+geo->numVertices);
insthead->indices = dstindices;
// TODO: morphing
MorphTarget *mt = geo->morphTargets;
for(i = 0; i < geo->numVertices; i++){
insthead->vertices[i].objVertex = mt->vertices[i];
if(geo->flags & Geometry::NORMALS)
insthead->vertices[i].objNormal = mt->normals[i];
else
insthead->vertices[i].objNormal = zeroNorm;
if(geo->flags & Geometry::PRELIT)
insthead->vertices[i].color = geo->colors[i];
else
insthead->vertices[i].color = black;
if(geo->numTexCoordSets > 0)
insthead->vertices[i].texCoords = geo->texCoords[0][i];
else
insthead->vertices[i].texCoords = zeroTex;
}
mesh = header->getMeshes();
for(i = 0; i < header->numMeshes; i++){
findMinVertAndNumVertices(mesh->indices, mesh->numIndices,
&firstVert, &inst->numVertices);
inst->indices = dstindices;
inst->vertices = &insthead->vertices[firstVert];
inst->mesh = mesh;
inst->material = mesh->material;
srcindices = mesh->indices;
if(header->flags & MeshHeader::TRISTRIP){
inst->numIndices = 0;
x = 0;
for(j = 0; j < mesh->numIndices-2; j++){
x1 = srcindices[j+x];
x ^= 1;
x2 = srcindices[j+x];
x3 = srcindices[j+2];
if(x1 != x2 && x2 != x3 && x1 != x3){
dstindices[0] = x1;
dstindices[1] = x2;
dstindices[2] = x3;
dstindices += 3;
inst->numIndices += 3;
}
}
}else{
inst->numIndices = mesh->numIndices;
for(j = 0; j < mesh->numIndices; j += 3){
dstindices[0] = srcindices[j+0] - firstVert;
dstindices[1] = srcindices[j+1] - firstVert;
dstindices[2] = srcindices[j+2] - firstVert;
dstindices += 3;
}
}
inst++;
mesh++;
}
}
struct MeshState
{
int32 flags;
Matrix obj2cam;
Matrix obj2world;
int32 numVertices;
int32 numPrimitives;
SurfaceProperties surfProps;
RGBA matCol;
};
static void
cam2screen(Im2DVertex *scrvert, CamSpace3DVertex *camvert)
{
RGBA col;
float32 recipZ;
Camera *cam = (Camera*)engine->currentCamera;
int32 width = cam->frameBuffer->width;
int32 height = cam->frameBuffer->height;
recipZ = 1.0f/camvert->camVertex.z;
scrvert->setScreenX(camvert->camVertex.x * recipZ * width);
scrvert->setScreenY(camvert->camVertex.y * recipZ * height);
// scrvert->setScreenX(camvert->camVertex.x * recipZ * width/2 + width/4);
// scrvert->setScreenY(camvert->camVertex.y * recipZ * height/2 + height/4);
scrvert->setScreenZ(recipZ * cam->zScale + cam->zShift);
scrvert->setCameraZ(camvert->camVertex.z);
scrvert->setRecipCameraZ(recipZ);
scrvert->setU(camvert->texCoords.u, recipZ);
scrvert->setV(camvert->texCoords.v, recipZ);
convColor(&col, &camvert->color);
scrvert->setColor(col.red, col.green, col.blue, col.alpha);
}
static void
transform(MeshState *mstate, ObjSpace3DVertex *objverts, CamSpace3DVertex *camverts, Im2DVertex *scrverts)
{
int32 i;
float32 z;
Camera *cam = (Camera*)engine->currentCamera;
for(i = 0; i < mstate->numVertices; i++){
V3d::transformPoints(&camverts[i].camVertex, &objverts[i].objVertex, 1, &mstate->obj2cam);
convColor(&camverts[i].color, &objverts[i].color);
camverts[i].texCoords = objverts[i].texCoords;
camverts[i].clipFlags = 0;
z = camverts[i].camVertex.z;
// 0 < x < z
if(camverts[i].camVertex.x >= z) camverts[i].clipFlags |= CLIPXHI;
if(camverts[i].camVertex.x <= 0) camverts[i].clipFlags |= CLIPXLO;
// 0 < y < z
if(camverts[i].camVertex.y >= z) camverts[i].clipFlags |= CLIPYHI;
if(camverts[i].camVertex.y <= 0) camverts[i].clipFlags |= CLIPYLO;
// near < z < far
if(z >= cam->farPlane) camverts[i].clipFlags |= CLIPZHI;
if(z <= cam->nearPlane) camverts[i].clipFlags |= CLIPZLO;
cam2screen(&scrverts[i], &camverts[i]);
}
}
static void
light(MeshState *mstate, ObjSpace3DVertex *objverts, CamSpace3DVertex *camverts)
{
int32 i;
RGBAf colf;
RGBAf amb = ambLight;
amb = scale(ambLight, mstate->surfProps.ambient);
for(i = 0; i < mstate->numVertices; i++){
camverts[i].color = add(camverts[i].color, amb);
if((mstate->flags & Geometry::NORMALS) == 0)
continue;
for(int32 k = 0; k < numDirectionals; k++){
float32 f = dot(objverts[i].objNormal, neg(directionals[k].at));
if(f <= 0.0f) continue;
f *= mstate->surfProps.diffuse;
colf = scale(directionals[k].color, f);
camverts[i].color = add(camverts[i].color, colf);
}
}
}
static void
postlight(MeshState *mstate, CamSpace3DVertex *camverts, Im2DVertex *scrverts)
{
int32 i;
RGBA col;
RGBAf colf;
for(i = 0; i < mstate->numVertices; i++){
convColor(&colf, &mstate->matCol);
camverts[i].color = modulate(camverts[i].color, colf);
clamp(&camverts[i].color);
convColor(&col, &camverts[i].color);
scrverts[i].setColor(col.red, col.green, col.blue, col.alpha);
}
}
static int32
cullTriangles(MeshState *mstate, CamSpace3DVertex *camverts, uint16 *indices, uint16 *clipindices)
{
int32 i;
int32 x1, x2, x3;
int32 newNumPrims;
int32 numClip;
newNumPrims = 0;
numClip = 0;
for(i = 0; i < mstate->numPrimitives; i++, indices += 3){
x1 = indices[0];
x2 = indices[1];
x3 = indices[2];
// Only a simple frustum call
if(camverts[x1].clipFlags &
camverts[x2].clipFlags &
camverts[x3].clipFlags)
continue;
if(camverts[x1].clipFlags |
camverts[x2].clipFlags |
camverts[x3].clipFlags)
numClip++;
// The Triangle is in, probably
clipindices[0] = x1;
clipindices[1] = x2;
clipindices[2] = x3;
clipindices += 3;
newNumPrims++;
}
mstate->numPrimitives = newNumPrims;
return numClip;
}
static void
interpVertex(CamSpace3DVertex *out, CamSpace3DVertex *v1, CamSpace3DVertex *v2, float32 t)
{
float32 z;
float32 invt;
Camera *cam = (Camera*)engine->currentCamera;
invt = 1.0f - t;
out->camVertex = add(scale(v1->camVertex, invt), scale(v2->camVertex, t));
out->color = add(scale(v1->color, invt), scale(v2->color, t));
out->texCoords.u = v1->texCoords.u*invt + v2->texCoords.u*t;
out->texCoords.v = v1->texCoords.v*invt + v2->texCoords.v*t;
out->clipFlags = 0;
z = out->camVertex.z;
// 0 < x < z
if(out->camVertex.x >= z) out->clipFlags |= CLIPXHI;
if(out->camVertex.x <= 0) out->clipFlags |= CLIPXLO;
// 0 < y < z
if(out->camVertex.y >= z) out->clipFlags |= CLIPYHI;
if(out->camVertex.y <= 0) out->clipFlags |= CLIPYLO;
// near < z < far
if(z >= cam->farPlane) out->clipFlags |= CLIPZHI;
if(z <= cam->nearPlane) out->clipFlags |= CLIPZLO;
}
static void
clipTriangles(MeshState *mstate, CamSpace3DVertex *camverts, Im2DVertex *scrverts, uint16 *indices, uint16 *clipindices)
{
int32 i, j;
int32 x1, x2, x3;
int32 newNumPrims;
CamSpace3DVertex buf[18];
CamSpace3DVertex *in, *out, *tmp;
int32 nin, nout;
float32 t;
Camera *cam = (Camera*)engine->currentCamera;
newNumPrims = 0;
for(i = 0; i < mstate->numPrimitives; i++, indices += 3){
x1 = indices[0];
x2 = indices[1];
x3 = indices[2];
if((camverts[x1].clipFlags |
camverts[x2].clipFlags |
camverts[x3].clipFlags) == 0){
// all inside
clipindices[0] = x1;
clipindices[1] = x2;
clipindices[2] = x3;
clipindices += 3;
newNumPrims++;
continue;
}
// set up triangle
in = &buf[0];
out = &buf[9];
in[0] = camverts[x1];
in[1] = camverts[x2];
in[2] = camverts[x3];
nin = 3;
nout = 0;
#define V(a) in[a].camVertex.
// clip z near
for(j = 0; j < nin; j++){
x1 = j;
x2 = (j+1) % nin;
if((in[x1].clipFlags ^ in[x2].clipFlags) & CLIPZLO){
t = (cam->nearPlane - V(x1)z)/(V(x2)z - V(x1)z);
interpVertex(&out[nout++], &in[x1], &in[x2], t);
}
if((in[x2].clipFlags & CLIPZLO) == 0)
out[nout++] = in[x2];
}
// clip z far
nin = nout; nout = 0;
tmp = in; in = out; out = tmp;
for(j = 0; j < nin; j++){
x1 = j;
x2 = (j+1) % nin;
if((in[x1].clipFlags ^ in[x2].clipFlags) & CLIPZHI){
t = (cam->farPlane - V(x1)z)/(V(x2)z - V(x1)z);
interpVertex(&out[nout++], &in[x1], &in[x2], t);
}
if((in[x2].clipFlags & CLIPZHI) == 0)
out[nout++] = in[x2];
}
// clip y 0
nin = nout; nout = 0;
tmp = in; in = out; out = tmp;
for(j = 0; j < nin; j++){
x1 = j;
x2 = (j+1) % nin;
if((in[x1].clipFlags ^ in[x2].clipFlags) & CLIPYLO){
t = -V(x1)y/(V(x2)y - V(x1)y);
interpVertex(&out[nout++], &in[x1], &in[x2], t);
}
if((in[x2].clipFlags & CLIPYLO) == 0)
out[nout++] = in[x2];
}
// clip y z
nin = nout; nout = 0;
tmp = in; in = out; out = tmp;
for(j = 0; j < nin; j++){
x1 = j;
x2 = (j+1) % nin;
if((in[x1].clipFlags ^ in[x2].clipFlags) & CLIPYHI){
t = (V(x1)z - V(x1)y)/(V(x1)z - V(x1)y + V(x2)y - V(x2)z);
interpVertex(&out[nout++], &in[x1], &in[x2], t);
}
if((in[x2].clipFlags & CLIPYHI) == 0)
out[nout++] = in[x2];
}
// clip x 0
nin = nout; nout = 0;
tmp = in; in = out; out = tmp;
for(j = 0; j < nin; j++){
x1 = j;
x2 = (j+1) % nin;
if((in[x1].clipFlags ^ in[x2].clipFlags) & CLIPXLO){
t = -V(x1)x/(V(x2)x - V(x1)x);
interpVertex(&out[nout++], &in[x1], &in[x2], t);
}
if((in[x2].clipFlags & CLIPXLO) == 0)
out[nout++] = in[x2];
}
// clip x z
nin = nout; nout = 0;
tmp = in; in = out; out = tmp;
for(j = 0; j < nin; j++){
x1 = j;
x2 = (j+1) % nin;
if((in[x1].clipFlags ^ in[x2].clipFlags) & CLIPXHI){
t = (V(x1)z - V(x1)x)/(V(x1)z - V(x1)x + V(x2)x - V(x2)z);
interpVertex(&out[nout++], &in[x1], &in[x2], t);
}
if((in[x2].clipFlags & CLIPXHI) == 0)
out[nout++] = in[x2];
}
// Insert new triangles
x1 = mstate->numVertices;
for(j = 0; j < nout; j++){
x2 = mstate->numVertices++;
camverts[x2] = out[j];
cam2screen(&scrverts[x2], &camverts[x2]);
}
x2 = x1+1;
for(j = 0; j < nout-2; j++){
clipindices[0] = x1;
clipindices[1] = x2++;
clipindices[2] = x2;
clipindices += 3;
newNumPrims++;
}
}
mstate->numPrimitives = newNumPrims;
}
static void
submitTriangles(RWDEVICE::Im2DVertex *scrverts, int32 numVerts, uint16 *indices, int32 numTris)
{
rw::SetRenderStatePtr(rw::TEXTURERASTER, nil);
if(dosoftras)
rastest_renderTriangles(scrverts, numVerts, indices, numTris);
else{
//int i;
//for(i = 0; i < numVerts; i++){
// scrverts[i].x = (int)(scrverts[i].x*16.0f) / 16.0f;
// scrverts[i].y = (int)(scrverts[i].y*16.0f) / 16.0f;
//}
im2d::RenderIndexedPrimitive(rw::PRIMTYPETRILIST, scrverts, numVerts,
indices, numTris*3);
}
}
static void
drawMesh(MeshState *mstate, ObjSpace3DVertex *objverts, uint16 *indices)
{
CamSpace3DVertex *camverts;
Im2DVertex *scrverts;
uint16 *cullindices, *clipindices;
uint32 numClip;
camverts = rwNewT(CamSpace3DVertex, mstate->numVertices, MEMDUR_FUNCTION);
scrverts = rwNewT(Im2DVertex, mstate->numVertices, MEMDUR_FUNCTION);
cullindices = rwNewT(uint16, mstate->numPrimitives*3, MEMDUR_FUNCTION);
transform(mstate, objverts, camverts, scrverts);
numClip = cullTriangles(mstate, camverts, indices, cullindices);
// int32 i;
// for(i = 0; i < mstate->numVertices; i++){
// if(camverts[i].clipFlags & CLIPX)
// camverts[i].color.red = 255;
// if(camverts[i].clipFlags & CLIPY)
// camverts[i].color.green = 255;
// if(camverts[i].clipFlags & CLIPZ)
// camverts[i].color.blue = 255;
// }
light(mstate, objverts, camverts);
// mstate->matCol.red = 255;
// mstate->matCol.green = 255;
// mstate->matCol.blue = 255;
postlight(mstate, camverts, scrverts);
// each triangle can have a maximum of 9 vertices (7 triangles) after clipping
// so resize to whatever we may need
camverts = rwResizeT(CamSpace3DVertex, camverts, mstate->numVertices + numClip*9, MEMDUR_FUNCTION);
scrverts = rwResizeT(Im2DVertex, scrverts, mstate->numVertices + numClip*9, MEMDUR_FUNCTION);
clipindices = rwNewT(uint16, mstate->numPrimitives*3 + numClip*7*3, MEMDUR_FUNCTION);
clipTriangles(mstate, camverts, scrverts, cullindices, clipindices);
submitTriangles(scrverts, mstate->numVertices, clipindices, mstate->numPrimitives);
rwFree(camverts);
rwFree(scrverts);
rwFree(cullindices);
rwFree(clipindices);
}
static void
drawAtomic(Atomic *atomic)
{
MeshState mstate;
Matrix lightmat;
Geometry *geo;
MeshHeader *header;
InstanceData *inst;
int i;
Camera *cam = (Camera*)engine->currentCamera;
instanceAtomic(atomic);
mstate.obj2world = *atomic->getFrame()->getLTM();
mstate.obj2cam = mstate.obj2world;
mstate.obj2cam.transform(&cam->viewMatrix, COMBINEPOSTCONCAT);
Matrix::invert(&lightmat, &mstate.obj2world);
enumLights(&lightmat);
geo = atomic->geometry;
header = geo->meshHeader;
inst = ((InstanceDataHeader*)geo->instData)->inst;
for(i = 0; i < header->numMeshes; i++){
mstate.flags = geo->flags;
mstate.numVertices = inst->numVertices;
mstate.numPrimitives = inst->numIndices / 3;
mstate.surfProps = inst->material->surfaceProps;
mstate.matCol = inst->material->color;
drawMesh(&mstate, inst->vertices, inst->indices);
inst++;
}
}
void
tlTest(Clump *clump)
{
FORLIST(lnk, clump->atomics){
Atomic *a = Atomic::fromClump(lnk);
drawAtomic(a);
}
}
}
static Im2DVertex *clipverts;
static int32 numClipverts;
void
genIm3DTransform(void *vertices, int32 numVertices, Matrix *world)
{
Im3DVertex *objverts;
V3d pos;
Matrix xform;
Camera *cam;
int32 i;
objverts = (Im3DVertex*)vertices;
cam = (Camera*)engine->currentCamera;
int32 width = cam->frameBuffer->width;
int32 height = cam->frameBuffer->height;
xform = cam->viewMatrix;
if(world)
xform.transform(world, COMBINEPRECONCAT);
clipverts = rwNewT(Im2DVertex, numVertices, MEMDUR_EVENT);
numClipverts = numVertices;
for(i = 0; i < numVertices; i++){
V3d::transformPoints(&pos, &objverts[i].position, 1, &xform);
float32 recipZ = 1.0f/pos.z;
RGBA c = objverts[i].getColor();
clipverts[i].setScreenX(pos.x * recipZ * width);
clipverts[i].setScreenY(pos.y * recipZ * height);
clipverts[i].setScreenZ(recipZ * cam->zScale + cam->zShift);
clipverts[i].setCameraZ(pos.z);
clipverts[i].setRecipCameraZ(recipZ);
clipverts[i].setColor(c.red, c.green, c.blue, c.alpha);
clipverts[i].setU(objverts[i].u, recipZ);
clipverts[i].setV(objverts[i].v, recipZ);
}
}
void
genIm3DRenderIndexed(PrimitiveType prim, void *indices, int32 numIndices)
{
im2d::RenderIndexedPrimitive(prim, clipverts, numClipverts, indices, numIndices);
}
void
genIm3DEnd(void)
{
rwFree(clipverts);
clipverts = nil;
numClipverts = 0;
}