First commit.

This commit is contained in:
Rinnegatamante
2020-09-26 10:28:55 +02:00
parent 2ed4eb3fe3
commit 8194094ec7
213 changed files with 83355 additions and 0 deletions
+145
View File
@@ -0,0 +1,145 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <rw.h>
using namespace std;
using namespace rw;
const char *chunks[] = { "None", "Struct", "String", "Extension", "Unknown",
"Camera", "Texture", "Material", "Material List", "Atomic Section",
"Plane Section", "World", "Spline", "Matrix", "Frame List",
"Geometry", "Clump", "Unknown", "Light", "Unicode String", "Atomic",
"Texture Native", "Texture Dictionary", "Animation Database",
"Image", "Skin Animation", "Geometry List", "Anim Animation",
"Team", "Crowd", "Delta Morph Animation", "Right To Render",
"MultiTexture Effect Native", "MultiTexture Effect Dictionary",
"Team Dictionary", "Platform Independet Texture Dictionary",
"Table of Contents", "Particle Standard Global Data", "AltPipe",
"Platform Independet Peds", "Patch Mesh", "Chunk Group Start",
"Chunk Group End", "UV Animation Dictionary", "Coll Tree"
};
/* From 0x0101 through 0x0135 */
const char *toolkitchunks0[] = { "Metrics PLG", "Spline PLG", "Stereo PLG",
"VRML PLG", "Morph PLG", "PVS PLG", "Memory Leak PLG", "Animation PLG",
"Gloss PLG", "Logo PLG", "Memory Info PLG", "Random PLG",
"PNG Image PLG", "Bone PLG", "VRML Anim PLG", "Sky Mipmap Val",
"MRM PLG", "LOD Atomic PLG", "ME PLG", "Lightmap PLG",
"Refine PLG", "Skin PLG", "Label PLG", "Particles PLG", "GeomTX PLG",
"Synth Core PLG", "STQPP PLG",
"Part PP PLG", "Collision PLG", "HAnim PLG", "User Data PLG",
"Material Effects PLG", "Particle System PLG", "Delta Morph PLG",
"Patch PLG", "Team PLG", "Crowd PP PLG", "Mip Split PLG",
"Anisotrophy PLG", "Not used", "GCN Material PLG", "Geometric PVS PLG",
"XBOX Material PLG", "Multi Texture PLG", "Chain PLG", "Toon PLG",
"PTank PLG", "Particle Standard PLG", "PDS PLG", "PrtAdv PLG",
"Normal Map PLG", "ADC PLG", "UV Animation PLG"
};
/* From 0x0180 through 0x01c1 */
const char *toolkitchunks1[] = {
"Character Set PLG", "NOHS World PLG", "Import Util PLG",
"Slerp PLG", "Optim PLG", "TL World PLG", "Database PLG",
"Raytrace PLG", "Ray PLG", "Library PLG",
"Not used", "Not used", "Not used", "Not used", "Not used", "Not used",
"2D PLG", "Tile Render PLG", "JPEG Image PLG", "TGA Image PLG",
"GIF Image PLG", "Quat PLG", "Spline PVS PLG", "Mipmap PLG",
"MipmapK PLG", "2D Font", "Intersection PLG", "TIFF Image PLG",
"Pick PLG", "BMP Image PLG", "RAS Image PLG", "Skin FX PLG",
"VCAT PLG", "2D Path", "2D Brush", "2D Object", "2D Shape", "2D Scene",
"2D Pick Region", "2D Object String", "2D Animation PLG",
"2D Animation",
"Not used", "Not used", "Not used", "Not used", "Not used", "Not used",
"2D Keyframe", "2D Maestro", "Barycentric",
"Platform Independent Texture Dictionary TK", "TOC TK", "TPL TK",
"AltPipe TK", "Animation TK", "Skin Split Tookit", "Compressed Key TK",
"Geometry Conditioning PLG", "Wing PLG", "Generic Pipeline TK",
"Lightmap Conversion TK", "Filesystem PLG", "Dictionary TK",
"UV Animation Linear", "UV Animation Parameter"
};
const char *RSchunks[] = { "Unused 1", "Unused 2", "Extra Normals",
"Pipeline Set", "Unused 5", "Unused 6", "Specular Material",
"Unused 8", "2dfx", "Extra Colors", "Collision Model",
"Unused 12", "Environment Material", "Breakable", "Node Name",
"Unused 16"
};
const char*
getChunkName(uint32 id)
{
switch(id){
case 0x50E:
return "Bin Mesh PLG";
case 0x510:
return "Native Data PLG";
case 0x511:
return "Vertex Format PLG";
case 0xF21E:
return "ZModeler Lock";
}
if(id <= 45)
return chunks[id];
else if(id <= 0x0253F2FF && id >= 0x0253F2F0)
return RSchunks[id-0x0253F2F0];
else if(id <= 0x0135 && id >= 0x0101)
return toolkitchunks0[id-0x0101];
else if(id <= 0x01C0 && id >= 0x0181)
return toolkitchunks1[id-0x0181];
else
return "Unknown";
}
void
readchunk(StreamFile *s, ChunkHeaderInfo *h, int level)
{
for(int i = 0; i < level; i++)
printf(" ");
const char *name = getChunkName(h->type);
printf("%s (%x bytes @ 0x%x/0x%x) - [0x%x]\n",
name, h->length, s->tell()-12, s->tell(), h->type);
uint32 end = s->tell() + h->length;
while(s->tell() < end){
ChunkHeaderInfo nh;
readChunkHeaderInfo(s, &nh);
if(nh.version == h->version && nh.build == h->build){
readchunk(s, &nh, level+1);
if(h->type == 0x510)
s->seek(end, 0);
}else{
s->seek(h->length-12);
break;
}
}
}
int
main(int argc, char *argv[])
{
if(argc < 2){
fprintf(stderr, "usage: %s rwStreamFile\n", argv[0]);
return 0;
}
StreamFile s;
s.open(argv[1], "rb");
ChunkHeaderInfo header, last;
while(readChunkHeaderInfo(&s, &header)){
if(header.type == 0)
break;
last = header;
if(argc == 2)
readchunk(&s, &header, 0);
}
printf("%x %x %x\n", last.version, last.build,
libraryIDPack(last.version, last.build));
s.close();
return 0;
}
+173
View File
@@ -0,0 +1,173 @@
#include <rw.h>
#include <skeleton.h>
#include <assert.h>
rw::V3d zero = { 0.0f, 0.0f, 0.0f };
struct SceneGlobals {
rw::World *world;
rw::Camera *camera;
} Scene;
rw::EngineOpenParams engineOpenParams;
void
Init(void)
{
sk::globals.windowtitle = "ImGui test";
sk::globals.width = 1280;
sk::globals.height = 800;
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;
}
bool
InitRW(void)
{
// rw::platform = rw::PLATFORM_D3D8;
if(!sk::InitRW())
return false;
Scene.world = rw::World::create();
rw::Light *ambient = rw::Light::create(rw::Light::AMBIENT);
ambient->setColor(0.2f, 0.2f, 0.2f);
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);
Scene.camera = sk::CameraCreate(sk::globals.width, sk::globals.height, 1);
Scene.world->addCamera(Scene.camera);
ImGui_ImplRW_Init();
ImGui::StyleColorsClassic();
return true;
}
void
Draw(float timeDelta)
{
static bool show_demo_window = true;
static bool show_another_window = false;
static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
rw::RGBA clearcol = rw::makeRGBA(clear_color.x*255, clear_color.y*255, clear_color.z*255, clear_color.w*255);
Scene.camera->clear(&clearcol, rw::Camera::CLEARIMAGE|rw::Camera::CLEARZ);
Scene.camera->beginUpdate();
ImGui_ImplRW_NewFrame(timeDelta);
// 1. Show a simple window.
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets automatically appears in a window called "Debug".
{
static float f = 0.0f;
ImGui::Text("Hello, world!"); // Some text (you can use a format string too)
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float as a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats as a color
if(ImGui::Button("Demo Window")) // Use buttons to toggle our bools. We could use Checkbox() as well.
show_demo_window ^= 1;
if(ImGui::Button("Another Window"))
show_another_window ^= 1;
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
}
// 2. Show another simple window. In most cases you will use an explicit Begin/End pair to name the window.
if(show_another_window){
ImGui::Begin("Another Window", &show_another_window);
ImGui::Text("Hello from another window!");
ImGui::End();
}
// 3. Show the ImGui demo window. Most of the sample code is in ImGui::ShowDemoWindow().
if(show_demo_window){
ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver); // Normally user code doesn't need/want to call this because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
ImGui::ShowDemoWindow(&show_demo_window);
}
ImGui::EndFrame();
ImGui::Render();
Scene.camera->endUpdate();
Scene.camera->showRaster(0);
}
void
KeyUp(int key)
{
}
void
KeyDown(int key)
{
switch(key){
case sk::KEY_ESC:
sk::globals.quit = 1;
break;
}
}
sk::EventStatus
AppEventHandler(sk::Event e, void *param)
{
using namespace sk;
Rect *r;
ImGuiEventHandler(e, param);
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 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;
// TODO: set aspect ratio
if(Scene.camera)
sk::CameraSize(Scene.camera, r);
break;
case IDLE:
Draw(*(float*)param);
return EVENTPROCESSED;
}
return sk::EVENTNOTPROCESSED;
}
Binary file not shown.
+365
View File
@@ -0,0 +1,365 @@
#include <rw.h>
#include <skeleton.h>
#include <assert.h>
rw::V3d zero = { 0.0f, 0.0f, 0.0f };
struct SceneGlobals {
rw::World *world;
rw::Camera *camera;
} Scene;
rw::EngineOpenParams engineOpenParams;
float FOV = 70.0f;
rw::V3d Xaxis = { 1.0f, 0.0, 0.0f };
rw::V3d Yaxis = { 0.0f, 1.0, 0.0f };
rw::V3d Zaxis = { 0.0f, 0.0, 1.0f };
rw::Light *BaseAmbientLight;
bool BaseAmbientLightOn;
rw::Light *CurrentLight;
rw::Light *AmbientLight;
rw::Light *PointLight;
rw::Light *DirectLight;
rw::Light *SpotLight;
rw::Light *SpotSoftLight;
float LightRadius = 100.0f;
float LightConeAngle = 45.0f;
rw::V3d LightPos = {0.0f, 0.0f, 75.0f};
void
Init(void)
{
sk::globals.windowtitle = "Light test";
sk::globals.width = 1280;
sk::globals.height = 800;
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;
}
rw::Light*
CreateBaseAmbientLight(void)
{
rw::Light *light = rw::Light::create(rw::Light::AMBIENT);
assert(light);
light->setColor(0.5f, 0.5f, 0.5f);
return light;
}
rw::Light*
CreateAmbientLight(void)
{
return rw::Light::create(rw::Light::AMBIENT);
}
rw::Light*
CreateDirectLight(void)
{
rw::Light *light = rw::Light::create(rw::Light::DIRECTIONAL);
assert(light);
rw::Frame *frame = rw::Frame::create();
assert(frame);
frame->rotate(&Xaxis, 45.0f, rw::COMBINEREPLACE);
rw::V3d pos = LightPos;
frame->translate(&pos, rw::COMBINEPOSTCONCAT);
light->setFrame(frame);
return light;
}
rw::Light*
CreatePointLight(void)
{
rw::Light *light = rw::Light::create(rw::Light::POINT);
assert(light);
light->radius = LightRadius;
rw::Frame *frame = rw::Frame::create();
assert(frame);
rw::V3d pos = LightPos;
frame->translate(&pos, rw::COMBINEREPLACE);
light->setFrame(frame);
return light;
}
rw::Light*
CreateSpotLight(void)
{
rw::Light *light = rw::Light::create(rw::Light::SPOT);
assert(light);
light->radius = LightRadius;
light->setAngle(LightConeAngle/180.0f*M_PI);
rw::Frame *frame = rw::Frame::create();
assert(frame);
frame->rotate(&Xaxis, 45.0f, rw::COMBINEREPLACE);
rw::V3d pos = LightPos;
frame->translate(&pos, rw::COMBINEPOSTCONCAT);
light->setFrame(frame);
return light;
}
rw::Light*
CreateSpotSoftLight(void)
{
rw::Light *light = rw::Light::create(rw::Light::SOFTSPOT);
assert(light);
light->radius = LightRadius;
light->setAngle(LightConeAngle/180.0f*M_PI);
rw::Frame *frame = rw::Frame::create();
assert(frame);
frame->rotate(&Xaxis, 45.0f, rw::COMBINEREPLACE);
rw::V3d pos = LightPos;
frame->translate(&pos, rw::COMBINEPOSTCONCAT);
light->setFrame(frame);
return light;
}
bool
CreateTestScene(rw::World *world)
{
rw::Clump *clump;
rw::StreamFile in;
const char *filename = "checker.dff";
if(in.open(filename, "rb") == NULL){
printf("couldn't open file\n");
return false;
}
if(!rw::findChunk(&in, rw::ID_CLUMP, NULL, NULL))
return false;
clump = rw::Clump::streamRead(&in);
in.close();
if(clump == nil)
return false;
rw::Clump *clone;
rw::Frame *clumpFrame;
rw::V3d pos;
float zOffset = 75.0f;
// Bottom panel
clumpFrame = clump->getFrame();
clumpFrame->rotate(&Xaxis, 90.0f, rw::COMBINEREPLACE);
pos.x = 0.0f;
pos.y = -25.0f;
pos.z = zOffset;
clumpFrame->translate(&pos, rw::COMBINEPOSTCONCAT);
// only need to add once
world->addClump(clump);
// Top panel
clone = clump->clone();
clumpFrame = clone->getFrame();
clumpFrame->rotate(&Xaxis, -90.0f, rw::COMBINEREPLACE);
pos.x = 0.0f;
pos.y = 25.0f;
pos.z = zOffset;
clumpFrame->translate(&pos, rw::COMBINEPOSTCONCAT);
// Left panel
clone = clump->clone();
clumpFrame = clone->getFrame();
clumpFrame->rotate(&Xaxis, 0.0f, rw::COMBINEREPLACE);
clumpFrame->rotate(&Yaxis, 90.0f, rw::COMBINEPOSTCONCAT);
pos.x = 25.0f;
pos.y = 0.0f;
pos.z = zOffset;
clumpFrame->translate(&pos, rw::COMBINEPOSTCONCAT);
// Right panel
clone = clump->clone();
clumpFrame = clone->getFrame();
clumpFrame->rotate(&Xaxis, 0.0f, rw::COMBINEREPLACE);
clumpFrame->rotate(&Yaxis, -90.0f, rw::COMBINEPOSTCONCAT);
pos.x = -25.0f;
pos.y = 0.0f;
pos.z = zOffset;
clumpFrame->translate(&pos, rw::COMBINEPOSTCONCAT);
// Back panel
clone = clump->clone();
clumpFrame = clone->getFrame();
clumpFrame->rotate(&Xaxis, 0.0f, rw::COMBINEREPLACE);
pos.x = 0.0f;
pos.y = 0.0f;
pos.z = zOffset + 25.0f;
clumpFrame->translate(&pos, rw::COMBINEPOSTCONCAT);
return 1;
}
bool
InitRW(void)
{
// rw::platform = rw::PLATFORM_D3D8;
if(!sk::InitRW())
return false;
Scene.world = rw::World::create();
BaseAmbientLight = CreateBaseAmbientLight();
AmbientLight = CreateAmbientLight();
DirectLight = CreateDirectLight();
PointLight = CreatePointLight();
SpotLight = CreateSpotLight();
SpotSoftLight = CreateSpotSoftLight();
Scene.camera = sk::CameraCreate(sk::globals.width, sk::globals.height, 1);
Scene.camera->setNearPlane(0.1f);
Scene.camera->setFarPlane(300.0f);
Scene.camera->setFOV(FOV, (float)sk::globals.width/sk::globals.height);
Scene.world->addCamera(Scene.camera);
CreateTestScene(Scene.world);
ImGui_ImplRW_Init();
ImGui::StyleColorsClassic();
return true;
}
void
SwitchToLight(rw::Light *light)
{
if(CurrentLight)
Scene.world->removeLight(CurrentLight);
CurrentLight = light;
Scene.world->addLight(CurrentLight);
}
void
Gui(void)
{
// ImGui::ShowDemoWindow(&show_demo_window);
static bool showLightWindow = true;
ImGui::Begin("Lights", &showLightWindow);
static int lightswitch = 0;
if(ImGui::RadioButton("Light Off", &lightswitch, 0)){
if(CurrentLight)
Scene.world->removeLight(CurrentLight);
CurrentLight = nil;
}
if(ImGui::RadioButton("Ambient Light", &lightswitch, 1)){
SwitchToLight(AmbientLight);
}
ImGui::SameLine();
if(ImGui::RadioButton("Directional Light", &lightswitch, 2)){
SwitchToLight(DirectLight);
}
ImGui::SameLine();
if(ImGui::RadioButton("Point Light", &lightswitch, 3)){
SwitchToLight(PointLight);
}
if(ImGui::RadioButton("Spot Light", &lightswitch, 4)){
SwitchToLight(SpotLight);
}
ImGui::SameLine();
if(ImGui::RadioButton("Soft Spot Light", &lightswitch, 5)){
SwitchToLight(SpotSoftLight);
}
ImGui::End();
}
void
Draw(float timeDelta)
{
static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
rw::RGBA clearcol = rw::makeRGBA(clear_color.x*255, clear_color.y*255, clear_color.z*255, clear_color.w*255);
Scene.camera->clear(&clearcol, rw::Camera::CLEARIMAGE|rw::Camera::CLEARZ);
Scene.camera->beginUpdate();
ImGui_ImplRW_NewFrame(timeDelta);
Scene.world->render();
Gui();
ImGui::EndFrame();
ImGui::Render();
Scene.camera->endUpdate();
Scene.camera->showRaster(0);
}
void
KeyUp(int key)
{
}
void
KeyDown(int key)
{
switch(key){
case sk::KEY_ESC:
sk::globals.quit = 1;
break;
}
}
sk::EventStatus
AppEventHandler(sk::Event e, void *param)
{
using namespace sk;
Rect *r;
ImGuiEventHandler(e, param);
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 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(Scene.camera){
sk::CameraSize(Scene.camera, r);
Scene.camera->setFOV(FOV, (float)sk::globals.width/sk::globals.height);
}
break;
case IDLE:
Draw(*(float*)param);
return EVENTPROCESSED;
}
return sk::EVENTNOTPROCESSED;
}
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
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
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
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");
}
*/
Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

+588
View File
@@ -0,0 +1,588 @@
#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);
void initsplines(void);
void rendersplines(void);
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);
}
}
#define MUL(x, y) ((x)*(y)/255)
int
calcVCfx(int fb, int col, int a, int iter)
{
int prev = fb;
int col2 = col*2;
if(col2 > 255) col2 = 255;
for(int i = 0; i < iter; i++){
int tmp = MUL(fb, 255-a) + MUL(MUL(prev, col2), a);
tmp += MUL(prev, col);
tmp += MUL(prev, col);
prev = tmp > 255 ? 255 : tmp;
}
return prev;
}
int
calcIIIfx(int fb, int col, int a, int iter)
{
int prev = fb;
for(int i = 0; i < iter; i++){
int tmp = MUL(fb, 255-a) + MUL(MUL(prev, col), a);
prev = tmp > 255 ? 255 : tmp;
}
return prev;
}
void
postfxtest(void)
{
rw::Image *img = rw::Image::create(256, 256, 32);
img->allocate();
int x, y;
int iter;
static char filename[100];
for(iter = 0; iter < 10; iter++){
for(y = 0; y < 256; y++)
for(x = 0; x < 256; x++){
int res = calcVCfx(y, x, 30, iter);
// int res = calcIIIfx(y, x, 30, iter);
if(0 && res == y){
img->pixels[y*img->stride + x*img->bpp + 0] = 255;
img->pixels[y*img->stride + x*img->bpp + 1] = 0;
img->pixels[y*img->stride + x*img->bpp + 2] = 0;
}else{
img->pixels[y*img->stride + x*img->bpp + 0] = res;
img->pixels[y*img->stride + x*img->bpp + 1] = res;
img->pixels[y*img->stride + x*img->bpp + 2] = res;
}
img->pixels[y*img->stride + x*img->bpp + 3] = 255;
}
sprintf(filename, "vcfx_%02d.bmp", iter);
// sprintf(filename, "iiifx_%02d.bmp", iter);
rw::writeBMP(img, filename);
}
exit(0);
}
bool
InitRW(void)
{
// rw::platform = rw::PLATFORM_D3D8;
if(!sk::InitRW())
return false;
rw::d3d::isP8supported = false;
postfxtest();
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 = 0.5f;
// 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);
initsplines();
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::EVERYTHING);
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 = { 161, 161, 161, 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);
rendersplines();
camera->m_rwcam->endUpdate();
camera->m_rwcam->showRaster(0);
}
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;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

+902
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->getScreenX() * 16.0f;
v[i].y = iv->getScreenY() * 16.0f;
v[i].z = 16777216*(1.0f-iv->getScreenZ());
v[i].q = iv->getRecipCameraZ();
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->getRecipCameraZ();
v[i].t = iv->v*iv->getRecipCameraZ();
}
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);
}
*/
+520
View File
@@ -0,0 +1,520 @@
#include <rw.h>
#include <skeleton.h>
#include <vector>
using namespace rw;
using namespace RWDEVICE;
static Im3DVertex im3dVerts[1024];
static int numImVerts;
static rw::PrimitiveType imPrim;
static Im3DVertex imVert;
void
BeginIm3D(rw::PrimitiveType prim)
{
numImVerts = 0;
imPrim = prim;
}
void
EndIm3D(void)
{
rw::im3d::Transform(im3dVerts, numImVerts, nil, rw::im3d::EVERYTHING);
rw::im3d::RenderPrimitive(imPrim);
rw::im3d::End();
}
void
AddVertex(const rw::V3d &vert)
{
if(numImVerts >= 1024){
EndIm3D();
switch(imPrim){
case PRIMTYPEPOLYLINE:
im3dVerts[0] = im3dVerts[numImVerts-1];
numImVerts = 1;
break;
case PRIMTYPETRISTRIP:
// TODO: winding?
im3dVerts[0] = im3dVerts[numImVerts-2];
im3dVerts[1] = im3dVerts[numImVerts-1];
numImVerts = 2;
break;
case PRIMTYPETRIFAN:
im3dVerts[1] = im3dVerts[numImVerts-1];
numImVerts = 2;
break;
default:
numImVerts = 0;
}
}
imVert.setX(vert.x);
imVert.setY(vert.y);
imVert.setZ(vert.z);
im3dVerts[numImVerts++] = imVert;
}
float epsilon = 0.000001;
class RBCurve
{
public:
int degree;
std::vector<V3d> verts;
std::vector<float> weights; // for rational
std::vector<float> knots;
V3d eval(float u);
void drawHull(void);
void drawSpline(void);
};
class RBSurf
{
public:
int degreeU, degreeV;
int numU, numV;
std::vector<V3d> verts;
std::vector<float> weights;
std::vector<float> knotsU, knotsV;
void update(void);
V3d eval(float u, float v);
void drawHull(void);
void drawIsoparms(void);
void drawShaded(void);
};
float div0(float a, float b) { return b == 0.0f ? a : a/b; }
// naive algorithm
float
evalBasis(int i, int d, float u, float knots[])
{
if(d == 0){
if(knots[i] <= u && u < knots[i+1])
return 1.0f;
return 0.0f;
}
float b0 = evalBasis(i, d-1, u, knots);
float b1 = evalBasis(i+1, d-1, u, knots);
return b0*div0(u-knots[i], knots[i+d] - knots[i]) + b1*div0(knots[i+d+1]-u, knots[i+d+1] - knots[i+1]);
}
float
evalBasisFast(int i, int d, float u, float knots[])
{
int r, j;
float tmp[10];
// degree 0 values
for(j = 0; j < d+1; j++)
tmp[j] = knots[i+j] <= u && u < knots[i+j+1] ? 1.0f : 0.0f;
// build up from degree zero
for(r = d, d = 1; r > 0; r--, d++){
for(j = 0; j < r; j++){
float t1 = div0(u-knots[i+j], knots[i+j + d] - knots[i+j]);
float t2 = div0(knots[i+j + d+1]-u, knots[i+j + d+1] - knots[i+j + 1]);
tmp[j] = tmp[j]*t1 + tmp[j+1]*t2;
}
}
return tmp[0];
}
V3d
RBCurve::eval(float u)
{
int i;
V3d vert = { 0.0f, 0.0f, 0.0f };
float w = 0.0f;
// Find knots we're interested in
for(i = 0; i < knots.size(); i++)
if(knots[i] <= u && u < knots[i+1])
break;
int startI = i-degree;
int endI = i+1;
for(i = startI; i < endI; i++){
float r = evalBasisFast(i, degree, u, &knots[0]);
w += weights[i]*r;
vert = add(vert, scale(verts[i], weights[i]*r));
}
return scale(vert, div0(1.0f,w));
}
void
RBCurve::drawHull(void)
{
int i;
rw::SetRenderState(rw::TEXTURERASTER, nil);
rw::SetRenderState(rw::FOGENABLE, 0);
BeginIm3D(rw::PRIMTYPEPOLYLINE);
imVert.setU(0.0f);
imVert.setV(0.0f);
imVert.setColor(138, 72, 51, 255);
// imVert.setColor(228, 172, 121, 255);
for(i = 0; i < verts.size(); i++)
AddVertex(verts[i]);
EndIm3D();
}
void
RBCurve::drawSpline(void)
{
int i;
float u, endu;
V3d vert;
rw::SetRenderState(rw::TEXTURERASTER, nil);
rw::SetRenderState(rw::FOGENABLE, 0);
BeginIm3D(rw::PRIMTYPEPOLYLINE);
imVert.setU(0.0f);
imVert.setV(0.0f);
imVert.setColor(0, 4, 96, 255);
u = knots[0];
endu = knots[knots.size()-1] - epsilon;
float uinc = (endu-knots[0])/40.0f;
for(;; u += uinc){
if(u > endu)
u = endu;
AddVertex(eval(u));
if(u >= endu)
break;
}
EndIm3D();
}
void
RBSurf::update(void)
{
numU = knotsU.size() - degreeU - 1;
numV = knotsV.size() - degreeV - 1;
}
V3d
RBSurf::eval(float u, float v)
{
int i, j;
V3d vert = { 0.0f, 0.0f, 0.0f };
float w = 0.0f;
float basisU[10], basisV[10];
// Find knots we're interested in
int k;
for(k = 0; k < knotsU.size(); k++)
if(knotsU[k] <= u && u < knotsU[k+1])
break;
int startI = k-degreeU;
int endI = k+1;
for(k = 0; k < knotsV.size(); k++)
if(knotsV[k] <= v && v < knotsV[k+1])
break;
int startJ = k-degreeV;
int endJ = k+1;
for(i = startI; i < endI; i++) basisU[i-startI] = evalBasisFast(i, degreeU, u, &knotsU[0]);
for(j = startJ; j < endJ; j++) basisV[j-startJ] = evalBasisFast(j, degreeV, v, &knotsV[0]);
for(j = startJ; j < endJ; j++)
for(i = startI; i < endI; i++){
float r = basisV[j-startJ]*basisU[i-startI];
w += weights[j*numU + i]*r;
vert = add(vert, scale(verts[j*numU + i], weights[j*numU + i]*r));
}
return scale(vert, div0(1.0f,w));
}
void
RBSurf::drawHull(void)
{
rw::SetRenderState(rw::TEXTURERASTER, nil);
rw::SetRenderState(rw::FOGENABLE, 0);
imVert.setU(0.0f);
imVert.setV(0.0f);
imVert.setColor(138, 72, 51, 255);
// imVert.setColor(228, 172, 121, 255);
int iu, iv;
for(iv = 0; iv < numV; iv++){
BeginIm3D(rw::PRIMTYPEPOLYLINE);
for(iu = 0; iu < numU; iu++)
AddVertex(verts[iu + iv*numU]);
EndIm3D();
}
for(iu = 0; iu < numU; iu++){
BeginIm3D(rw::PRIMTYPEPOLYLINE);
for(iv = 0; iv < numV; iv++)
AddVertex(verts[iu + iv*numU]);
EndIm3D();
}
}
void
RBSurf::drawIsoparms(void)
{
V3d vert;
int iu, iv;
float u, v;
rw::SetRenderState(rw::TEXTURERASTER, nil);
rw::SetRenderState(rw::FOGENABLE, 0);
imVert.setU(0.0f);
imVert.setV(0.0f);
imVert.setColor(0, 4, 96, 255);
float endu = knotsU[knotsU.size()-1] - epsilon;
float endv = knotsU[knotsV.size()-1] - epsilon;
float uinc = (endu-knotsU[0])/40.0f;
float vinc = (endv-knotsV[0])/40.0f;
v = -100000.0f;
for(iv = 0; iv < knotsV.size(); iv++){
if(knotsV[iv] <= v) continue;
v = knotsV[iv];
if(v > endv) v = endv;
BeginIm3D(rw::PRIMTYPEPOLYLINE);
for(u = knotsU[0];; u += uinc){
if(u > endu)
u = endu;
AddVertex(eval(u, v));
if(u >= endu)
break;
}
EndIm3D();
}
u = -100000.0f;
for(iu = 0; iu < knotsU.size(); iu++){
if(knotsU[iu] <= u) continue;
u = knotsU[iu];
if(u > endu) u = endu;
BeginIm3D(rw::PRIMTYPEPOLYLINE);
for(v = knotsV[0];; v += vinc){
if(v > endv)
v = endv;
AddVertex(eval(u, v));
if(v >= endv)
break;
}
EndIm3D();
}
}
void
RBSurf::drawShaded(void)
{
V3d vert;
int iu, iv;
float u, v;
rw::SetRenderState(rw::TEXTURERASTER, nil);
rw::SetRenderState(rw::FOGENABLE, 0);
imVert.setU(0.0f);
imVert.setV(0.0f);
imVert.setColor(0, 128, 240, 255);
float endu = knotsU[knotsU.size()-1] - epsilon;
float endv = knotsU[knotsV.size()-1] - epsilon;
float uinc = (endu-knotsU[0])/40.0f;
float vinc = (endv-knotsV[0])/40.0f;
float vnext;
for(v = knotsV[0];; v = vnext){
if(v > endv)
v = endv;
vnext = v + vinc;
BeginIm3D(rw::PRIMTYPETRISTRIP);
for(u = knotsU[0];; u += uinc){
if(u > endu)
u = endu;
AddVertex(eval(u, v));
AddVertex(eval(u, vnext));
if(u >= endu)
break;
}
EndIm3D();
if(vnext >= endv)
break;
}
}
RBCurve testspline1, testspline2;
RBSurf testsurf;
void
initsplines(void)
{
V3d vert;
testspline1.degree = 3;
testspline1.verts.clear();
testspline1.weights.clear();
vert.set(-30.63383, 22.65459, 0);
vert = scale(vert, 1.0f/20.0f);
testspline1.verts.push_back(vert);
testspline1.weights.push_back(1.0f);
vert.set(13.50783, 33.01786, 15.06403);
vert = scale(vert, 1.0f/20.0f);
testspline1.verts.push_back(vert);
testspline1.weights.push_back(1.0f);
vert.set(34.252, -10.36327, 15.06403);
vert = scale(vert, 1.0f/20.0f);
testspline1.verts.push_back(vert);
testspline1.weights.push_back(1.0f);
vert.set(-7.959972, -1.205032, 0);
vert = scale(vert, 1.0f/20.0f);
testspline1.verts.push_back(vert);
testspline1.weights.push_back(1.0f);
vert.set(6.995127, -41.32158, -18.19684);
vert = scale(vert, 1.0f/20.0f);
testspline1.verts.push_back(vert);
testspline1.weights.push_back(1.0f);
testspline1.knots.clear();
testspline1.knots.push_back(0);
testspline1.knots.push_back(0);
testspline1.knots.push_back(0);
testspline1.knots.push_back(0);
testspline1.knots.push_back(1);
testspline1.knots.push_back(2);
testspline1.knots.push_back(2);
testspline1.knots.push_back(2);
testspline1.knots.push_back(2);
testspline2.degree = 2;
testspline2.verts.clear();
#define V(x, y, z) \
vert.set(x, y, z); \
testspline2.verts.push_back(scale(vert, 1.0f/20.0f)); \
testspline2.weights.push_back(1.0f);
V(-61.9913, 9.158239, 0);
V(-32.32231, 27.23371, 0);
V(25.80961, -4.820126, 0);
testspline2.knots.clear();
testspline2.knots.push_back(0);
testspline2.knots.push_back(0);
testspline2.knots.push_back(0);
testspline2.knots.push_back(1);
testspline2.knots.push_back(1);
testspline2.knots.push_back(1);
/*
testspline2 = testspline1;
// testspline2.knots.clear();
// testspline2.knots.push_back(0);
// testspline2.knots.push_back(0);
// testspline2.knots.push_back(0);
// testspline2.knots.push_back(0);
// testspline2.knots.push_back(3);
// testspline2.knots.push_back(4);
// testspline2.knots.push_back(4);
// testspline2.knots.push_back(4);
// testspline2.knots.push_back(4);
testspline1.weights[2] = 5.0f;
*/
#define V(x, y, z) \
vert.set(x, y, z); \
testsurf.verts.push_back(scale(vert, 1.0f/20.0f)); \
testsurf.weights.push_back(1.0f);
testsurf.degreeU = 3;
testsurf.degreeV = 3;
testsurf.verts.clear();
testsurf.weights.clear();
V(-69.22764, -0, 12.77366);
V(-48.72468, 0, 29.16251);
V(-24.84476, 0, 39.52605);
V(22.43265, -0, 45.79238);
V(36.4229, 0, 28.9215);
V(61.02645, 0, 6.74835);
V(86.35364, -0, 20.96809);
V(-69.22764, 9.286676, 12.77366);
V(-48.72468, 9.286676, 29.16251);
V(-24.84476, 9.286676, 39.52605);
V(22.43265, 9.286676, 45.79238);
V(36.4229, 9.286676, 28.9215);
V(61.02645, 9.286676, 6.74835);
V(86.35364, 9.286676, 20.96809);
V(-68.13416, 23.51821, 6.114491);
V(-48.19925, 23.51821, 22.27994);
V(-26.91943, 23.51821, 33.20763);
V(18.69658, 23.51821, 39.0488);
V(27.88844, 23.51821, 30.80604);
V(57.49908, 23.51821, -0.6488895);
V(86.35364, 23.51821, 14.21974);
V(-67.00163, 52.46369, -0.7825046);
V(-47.65504, 52.46369, 15.15157);
V(-29.06818, 52.46369, 26.66356);
V(14.82709, 52.46369, 32.06438);
V(19.04919, 52.46369, 32.75788);
V(53.84574, 52.46369, -8.310311);
V(86.35364, 52.46369, 7.230374);
V(-67.86079, 70.07219, 4.449699);
V(-48.06789, 70.07219, 20.5593);
V(-27.43809, 70.07219, 31.62803);
V(17.76257, 70.07219, 37.36291);
V(25.75483, 70.07219, 31.27717);
V(56.61724, 70.07219, -2.498198);
V(86.35364, 70.07219, 12.53265);
testsurf.knotsU.clear();
testsurf.knotsU.push_back(0);
testsurf.knotsU.push_back(0);
testsurf.knotsU.push_back(0);
testsurf.knotsU.push_back(0);
testsurf.knotsU.push_back(0.25);
testsurf.knotsU.push_back(0.5);
testsurf.knotsU.push_back(0.75);
testsurf.knotsU.push_back(1);
testsurf.knotsU.push_back(1);
testsurf.knotsU.push_back(1);
testsurf.knotsU.push_back(1);
testsurf.knotsV.clear();
testsurf.knotsV.push_back(0);
testsurf.knotsV.push_back(0);
testsurf.knotsV.push_back(0);
testsurf.knotsV.push_back(0);
testsurf.knotsV.push_back(0.5);
testsurf.knotsV.push_back(1);
testsurf.knotsV.push_back(1);
testsurf.knotsV.push_back(1);
testsurf.knotsV.push_back(1);
testsurf.update();
}
void
rendersplines(void)
{
testspline1.drawHull();
testspline1.drawSpline();
// testspline2.drawHull();
// testspline2.drawSpline();
testsurf.drawHull();
testsurf.drawShaded();
testsurf.drawIsoparms();
}
Binary file not shown.
+662
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;
}
+437
View File
@@ -0,0 +1,437 @@
#define GS_NONINTERLACED 0
#define GS_INTERLACED 1
#define GS_NTSC 2
#define GS_PAL 3
#define GS_VESA1A 0x1a
#define GS_VESA1B 0x1b
#define GS_VESA1C 0x1c
#define GS_VESA1D 0x1d
#define GS_VESA2A 0x2a
#define GS_VESA2B 0x2b
#define GS_VESA2C 0x2c
#define GS_VESA2D 0x2d
#define GS_VESA2E 0x2e
#define GS_VESA3B 0x3b
#define GS_VESA3C 0x3c
#define GS_VESA3D 0x3d
#define GS_VESA3E 0x3e
#define GS_VESA4A 0x4a
#define GS_VESA4B 0x4b
#define GS_DTV480P 0x50
#define GS_FIELD 0
#define GS_FRAME 1
#define GS_PSMCT32 0
#define GS_PSMCT24 1
#define GS_PSMCT16 2
#define GS_PSMCT16S 10
#define GS_PS_GPU24 18
#define GS_PSMZ32 0
#define GS_PSMZ24 1
#define GS_PSMZ16 2
#define GS_PSMZ16S 10
#define GS_ZTST_NEVER 0
#define GS_ZTST_ALWAYS 1
#define GS_ZTST_GREATER 2
#define GS_ZTST_GEQUAL 3
#define GS_PRIM_POINT 0
#define GS_PRIM_LINE 1
#define GS_PRIM_LINE_STRIP 2
#define GS_PRIM_TRI 3
#define GS_PRIM_TRI_STRIP 4
#define GS_PRIM_TRI_FAN 5
#define GS_PRIM_SPRITE 6
#define GS_PRIM_NO_SPEC 7
#define GS_IIP_FLAT 0
#define GS_IIP_GOURAUD 1
/* GS general purpose registers */
#define GS_PRIM 0x00
#define GS_RGBAQ 0x01
#define GS_ST 0x02
#define GS_UV 0x03
#define GS_XYZF2 0x04
#define GS_XYZ2 0x05
#define GS_TEX0_1 0x06
#define GS_TEX0_2 0x07
#define GS_CLAMP_1 0x08
#define GS_CLAMP_2 0x09
#define GS_FOG 0x0a
#define GS_XYZF3 0x0c
#define GS_XYZ3 0x0d
#define GS_TEX1_1 0x14
#define GS_TEX1_2 0x15
#define GS_TEX2_1 0x16
#define GS_TEX2_2 0x17
#define GS_XYOFFSET_1 0x18
#define GS_XYOFFSET_2 0x19
#define GS_PRMODECONT 0x1a
#define GS_PRMODE 0x1b
#define GS_TEXCLUT 0x1c
#define GS_SCANMSK 0x22
#define GS_MIPTBP1_1 0x34
#define GS_MIPTBP1_2 0x35
#define GS_MIPTBP2_1 0x36
#define GS_MIPTBP2_2 0x37
#define GS_TEXA 0x3b
#define GS_FOGCOL 0x3d
#define GS_TEXFLUSH 0x3f
#define GS_SCISSOR_1 0x40
#define GS_SCISSOR_2 0x41
#define GS_ALPHA_1 0x42
#define GS_ALPHA_2 0x43
#define GS_DIMX 0x44
#define GS_DTHE 0x45
#define GS_COLCLAMP 0x46
#define GS_TEST_1 0x47
#define GS_TEST_2 0x48
#define GS_PABE 0x49
#define GS_FBA_1 0x4a
#define GS_FBA_2 0x4b
#define GS_FRAME_1 0x4c
#define GS_FRAME_2 0x4d
#define GS_ZBUF_1 0x4e
#define GS_ZBUF_2 0x4f
#define GS_BITBLTBUF 0x50
#define GS_TRXPOS 0x51
#define GS_TRXREG 0x52
#define GS_TRXDIR 0x53
#define GS_HWREG 0x54
#define GS_SIGNAL 0x60
#define GS_FINISH 0x61
#define GS_LABEL 0x62
typedef union
{
struct {
uint64 EN1 : 1;
uint64 EN2 : 1;
uint64 CRTMD : 3;
uint64 MMOD : 1;
uint64 AMOD : 1;
uint64 SLBG : 1;
uint64 ALP : 8;
} f;
uint64 d;
} GsPmode;
#define GS_MAKE_PMODE(EN1,EN2,MMOD,AMOD,SLBG,ALP) \
(BIT64(EN1,0) | BIT64(EN2,1) | BIT64(1,2) | \
BIT64(MMOD,5) | BIT64(AMOD,6) | BIT64(SLBG,7) | BIT64(ALP,8))
typedef union
{
struct {
uint64 INT : 1;
uint64 FFMD : 1;
uint64 DPMS : 2;
} f;
uint64 d;
} GsSmode2;
#define GS_MAKE_SMODE2(INT,FFMD,DPMS) \
(BIT64(INT,0) | BIT64(FFMD,1) | BIT64(DPMS,2))
typedef union
{
struct {
uint64 FBP : 9;
uint64 FBW : 6;
uint64 PSM : 5;
uint64 : 12;
uint64 DBX : 11;
uint64 DBY : 11;
} f;
uint64 d;
} GsDispfb;
#define GS_MAKE_DISPFB(FBP,FBW,PSM,DBX,DBY) \
(BIT64(FBP,0) | BIT64(FBW,9) | BIT64(PSM,15) | \
BIT64(DBX,32) | BIT64(DBY,43))
typedef union
{
struct {
uint64 DX : 12;
uint64 DY : 11;
uint64 MAGH : 4;
uint64 MAGV : 2;
uint64 : 3;
uint64 DW : 12;
uint64 DH : 11;
} f;
uint64 d;
} GsDisplay;
#define GS_MAKE_DISPLAY(DX,DY,MAGH,MAGV,DW,DH) \
(BIT64(DX,0) | BIT64(DY,12) | BIT64(MAGH,23) | \
BIT64(MAGV,27) | BIT64(DW,32) | BIT64(DH,44))
typedef union
{
struct {
uint64 EXBP : 14;
uint64 EXBW : 6;
uint64 FBIN : 2;
uint64 WFFMD : 1;
uint64 EMODA : 2;
uint64 EMODC : 2;
uint64 : 5;
uint64 WDX : 11;
uint64 WDY : 11;
} f;
uint64 d;
} GsExtbuf;
#define GS_MAKE_EXTBUF(EXBP,EXBW,FBIN,WFFMD,EMODA,EMODC,WDX,WDY) \
(BIT64(EXBP,0) | BIT64(EXBW,14) | BIT64(FBIN,20) | \
BIT64(WFFMD,22) | BIT64(EMODA,23) | BIT64(EMODC,25) | \
BIT64(WDX,32) | BIT64(WDY,43))
typedef union
{
struct {
uint64 SX : 12;
uint64 SY : 11;
uint64 SMPH : 4;
uint64 SMPV : 2;
uint64 : 3;
uint64 WW : 12;
uint64 WH : 11;
} f;
uint64 d;
} GsExtdata;
#define GS_MAKE_EXTDATA(SX,SY,SMPH,SMPV,WW,WH) \
(BIT64(SX,0) | BIT64(SY,12) | BIT64(SMPH,23) | \
BIT64(SMPV,27) | BIT64(WW,32) | BIT64(WH,44))
typedef union
{
struct {
uint64 WRITE : 1;
} f;
uint64 d;
} GsExtwrite;
typedef union
{
struct {
uint64 R : 8;
uint64 G : 8;
uint64 B : 8;
} f;
uint64 d;
} GsBgcolor;
#define GS_MAKE_BGCOLOR(R,G,B) \
(BIT64(R,0) | BIT64(G,8) | BIT64(B,16))
typedef union
{
struct {
uint64 SIGNAL : 1;
uint64 FINISH : 1;
uint64 HSINT : 1;
uint64 VSINT : 1;
uint64 EDWINT : 1;
uint64 : 3;
uint64 FLUSH : 1;
uint64 RESET : 1;
uint64 : 2;
uint64 NFIELD : 1;
uint64 FIELD : 1;
uint64 FIFO : 2;
uint64 REV : 8;
uint64 ID : 8;
} f;
uint64 d;
} GsCsr;
#define GS_CSR_SIGNAL_O 0
#define GS_CSR_FINISH_O 1
#define GS_CSR_HSINT_O 2
#define GS_CSR_VSINT_O 3
#define GS_CSR_EDWINT_O 4
#define GS_CSR_FLUSH_O 8
#define GS_CSR_RESET_O 9
#define GS_CSR_NFIELD_O 12
#define GS_CSR_FIELD_O 13
#define GS_CSR_FIFO_O 14
#define GS_CSR_REV_O 16
#define GS_CSR_ID_O 24
typedef union
{
struct {
uint64 : 8;
uint64 SIGMSK : 1;
uint64 FINISHMSK : 1;
uint64 HSMSKMSK : 1;
uint64 VSMSKMSK : 1;
uint64 EDWMSKMSK : 1;
} f;
uint64 d;
} GsImr;
typedef union
{
struct {
uint64 DIR : 1;
} f;
uint64 d;
} GsBusdir;
typedef union
{
struct {
uint64 SIGID : 32;
uint64 LBLID : 32;
} f;
uint64 d;
} GsSiglblid;
typedef union
{
struct {
uint64 FBP : 9;
uint64 : 7;
uint64 FBW : 6;
uint64 : 2;
uint64 PSM : 6;
uint64 : 2;
uint64 FBMSK : 32;
} f;
uint64 d;
} GsFrame;
#define GS_MAKE_FRAME(FBP,FBW,PSM,FBMASK) \
(BIT64(FBP,0) | BIT64(FBW,16) | BIT64(PSM,24) | BIT64(FBMASK,32))
typedef union
{
struct {
uint64 ZBP : 9;
uint64 : 15;
uint64 PSM : 4;
uint64 : 4;
uint64 ZMSDK : 1;
} f;
uint64 d;
} GsZbuf;
#define GS_MAKE_ZBUF(ZBP,PSM,ZMSK) \
(BIT64(ZBP,0) | BIT64(PSM,24) | BIT64(ZMSK,32))
typedef union
{
struct {
uint64 OFX : 16;
uint64 : 16;
uint64 OFY : 16;
} f;
uint64 d;
} GsXyOffset;
#define GS_MAKE_XYOFFSET(OFX,OFY) \
(BIT64(OFX,0) | BIT64(OFY,32))
typedef union
{
struct {
uint64 SCAX0 : 11;
uint64 : 5;
uint64 SCAX1 : 11;
uint64 : 5;
uint64 SCAY0 : 11;
uint64 : 5;
uint64 SCAY1 : 11;
} f;
uint64 d;
} GsScissor;
#define GS_MAKE_SCISSOR(SCAX0,SCAX1,SCAY0,SCAY1) \
(BIT64(SCAX0,0) | BIT64(SCAX1,16) | BIT64(SCAY0,32) | BIT64(SCAY1,48))
#define GS_MAKE_TEST(ATE,ATST,AREF,AFAIL,DATE,DATM,ZTE,ZTST) \
(BIT64(ATE,0) | BIT64(ATST,1) | BIT64(AREF,4) | BIT64(AFAIL,12) | \
BIT64(DATE,14) | BIT64(DATM,15) | BIT64(ZTE,16) | BIT64(ZTST,17))
#define GS_MAKE_PRIM(PRIM,IIP,TME,FGE,ABE,AA1,FST,CTXT,FIX) \
(BIT64(PRIM,0) | BIT64(IIP,3) | BIT64(TME,4) | BIT64(FGE,5) | \
BIT64(ABE,6) | BIT64(AA1,7) | BIT64(FST,8) | BIT64(CTXT,9) | BIT64(FIX,10))
#define GS_MAKE_RGBAQ(R,G,B,A,Q) \
(BIT64(R,0) | BIT64(G,8) | BIT64(B,16) | BIT64(A,24) | BIT64(Q,32))
#define GS_MAKE_XYZ(X,Y,Z) \
(BIT64(X,0) | BIT64(Y,16) | BIT64(Z,32))
#define GIF_PACKED 0
#define GIF_REGLIST 1
#define GIF_IMAGE 2
#define GIF_MAKE_TAG(NLOOP,EOP,PRE,PRIM,FLG,NREG) \
(BIT64(NLOOP,0) | BIT64(EOP,15) | BIT64(PRE,46) | \
BIT64(PRIM,47) | BIT64(FLG,58) | BIT64(NREG,60))
/* This is global and not tied to a user context because
* it is set up by kernel functions and not really changed
* afterwards. */
typedef struct GsCrtState GsCrtState;
struct GsCrtState
{
short inter, mode, ff;
};
extern GsCrtState gsCrtState;
typedef struct GsDispCtx GsDispCtx;
struct GsDispCtx
{
// two circuits
GsPmode pmode;
GsDispfb dispfb1;
GsDispfb dispfb2;
GsDisplay display1;
GsDisplay display2;
GsBgcolor bgcolor;
};
typedef struct GsDrawCtx GsDrawCtx;
struct GsDrawCtx
{
//two contexts
uint128 gifTag;
GsFrame frame1;
uint64 ad_frame1;
GsFrame frame2;
uint64 ad_frame2;
GsZbuf zbuf1;
uint64 ad_zbuf1;
GsZbuf zbuf2;
uint64 ad_zbuf2;
GsXyOffset xyoffset1;
uint64 ad_xyoffset1;
GsXyOffset xyoffset2;
uint64 ad_xyoffset2;
GsScissor scissor1;
uint64 ad_scissor1;
GsScissor scissor2;
uint64 ad_scissor2;
};
typedef struct GsCtx GsCtx;
struct GsCtx
{
// display context; two buffers
GsDispCtx disp[2];
// draw context; two buffers
GsDrawCtx draw[2];
};
+787
View File
@@ -0,0 +1,787 @@
#include <cstdio>
#include <cassert>
#define PAL
#include <rw.h>
using rw::uint8;
using rw::uint16;
using rw::uint32;
using rw::uint64;
using rw::int8;
using rw::int16;
using rw::int32;
using rw::int64;
using rw::bool32;
using rw::float32;
typedef uint8 uchar;
typedef uint16 ushort;
typedef uint32 uint;
#define WIDTH 640
#ifdef PAL
#define HEIGHT 512
#define VMODE GS_PAL
#else
#define HEIGHT 448
#define VMODE GS_NTSC
#endif
#include "ps2.h"
// getting undefined references otherwise :/
int *__errno() { return &errno; }
// NONINTERLACED and FRAME have half of the FIELD vertical resolution!
// NONINTERLACED has half the vertical units
uint128 packetbuf[128];
uint128 vuXYZScale;
uint128 vuXYZOffset;
extern uint32 geometryCall[];
extern uint32 skinPipe[];
uint128 *curVifPtr;
uint128 lightpacket[128];
int32 numLightQ;
rw::World *world;
rw::Camera *camera;
int frames;
void
printquad(uint128 p)
{
uint64 *lp;
lp = (uint64*)&p;
printf("%016lx %016lx\n", lp[1], lp[0]);
}
void
printquad4(uint128 p)
{
uint32 *lp;
lp = (uint32*)&p;
printf("%08x %08x %08x %08x\n", lp[0], lp[1], lp[2], lp[3]);
}
void
dump4(uint128 *p, int n)
{
printf("data at %p\n", p);
while(n--)
printquad4(*p++);
}
struct DmaChannel {
uint32 chcr; uint32 pad0[3];
uint32 madr; uint32 pad1[3];
uint32 qwc; uint32 pad2[3];
uint32 tadr; uint32 pad3[3];
uint32 asr0; uint32 pad4[3];
uint32 asr1; uint32 pad5[3];
uint32 pad6[8];
uint32 sadr;
};
static struct DmaChannel *dmaChannels[] = {
(struct DmaChannel *) &D0_CHCR,
(struct DmaChannel *) &D1_CHCR,
(struct DmaChannel *) &D2_CHCR,
(struct DmaChannel *) &D3_CHCR,
(struct DmaChannel *) &D4_CHCR,
(struct DmaChannel *) &D5_CHCR,
(struct DmaChannel *) &D6_CHCR,
(struct DmaChannel *) &D7_CHCR,
(struct DmaChannel *) &D8_CHCR,
(struct DmaChannel *) &D9_CHCR
};
void
dmaReset(void)
{
/* don't clear the SIF channels */
int doclear[] = { 1, 1, 1, 1, 1, 0, 0, 0, 1, 1 };
int i;
D_CTRL = 0;
for(i = 0; i < 10; i++)
if(doclear[i]){
dmaChannels[i]->chcr = 0;
dmaChannels[i]->madr = 0;
dmaChannels[i]->qwc = 0;
dmaChannels[i]->tadr = 0;
dmaChannels[i]->asr0 = 0;
dmaChannels[i]->asr1 = 0;
dmaChannels[i]->sadr = 0;
}
D_CTRL = 1;
}
void
waitDMA(volatile uint32 *chcr)
{
while(*chcr & (1<<8));
}
void
qwcpy(uint128 *dst, uint128 *src, int n)
{
while(n--) *dst++ = *src++;
}
void
toGIF(void *src, int n)
{
FlushCache(0);
D2_QWC = n;
D2_MADR = (uint32)src;
D2_CHCR = 1<<8;
waitDMA(&D2_CHCR);
}
void
toGIFchain(void *src)
{
FlushCache(0);
D2_QWC = 0;
D2_TADR = (uint32)src & 0x0FFFFFFF;
D2_CHCR = 1<<0 | 1<<2 | 1<<6 | 1<<8;
waitDMA(&D2_CHCR);
}
void
toVIF1chain(void *src)
{
FlushCache(0);
D1_QWC = 0;
D1_TADR = (uint32)src & 0x0FFFFFFF;
D1_CHCR = 1<<0 | 1<<2 | 1<<6 | 1<<8;
waitDMA(&D1_CHCR);
}
GsCrtState gsCrtState;
int psmsizemap[64] = {
4, // GS_PSMCT32
4, // GS_PSMCT24
2, // GS_PSMCT16
0, 0, 0, 0, 0, 0, 0,
2, // GS_PSMCT16S
0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, // GS_PSMZ32
4, // GS_PSMZ24
2, // GS_PSMZ16
2, // GS_PSMZ16S
0, 0, 0, 0, 0
};
void
GsResetCrt(uchar inter, uchar mode, uchar ff)
{
gsCrtState.inter = inter;
gsCrtState.mode = mode;
gsCrtState.ff = ff;
GS_CSR = 1 << GS_CSR_RESET_O;
__asm__("sync.p; nop");
GsPutIMR(0xff00);
SetGsCrt(gsCrtState.inter, gsCrtState.mode, gsCrtState.ff);
}
uint gsAllocPtr = 0;
void
GsInitDispCtx(GsDispCtx *disp, int width, int height, int psm)
{
int magh, magv;
int dx, dy;
int dw, dh;
dx = gsCrtState.mode == GS_NTSC ? 636 : 656;
dy = gsCrtState.mode == GS_NTSC ? 25 : 36;
magh = 2560/width - 1;
magv = 0;
dw = 2560-1;
dh = height-1;
if(gsCrtState.inter == GS_INTERLACED){
dy *= 2;
if(gsCrtState.ff == GS_FRAME)
dh = (dh+1)*2-1;
}
disp->pmode.d = GS_MAKE_PMODE(0, 1, 1, 1, 0, 0x00);
// disp->bgcolor.d = 0x404040;
disp->bgcolor.d = 0x000000;
disp->dispfb1.d = 0;
disp->dispfb2.d = GS_MAKE_DISPFB(0, width/64, psm, 0, 0);
disp->display1.d = 0;
disp->display2.d = GS_MAKE_DISPLAY(dx, dy, magh, magv, dw, dh);
}
void
GsPutDispCtx(GsDispCtx *disp)
{
GS_PMODE = disp->pmode.d;
GS_DISPFB1 = disp->dispfb1.d;
GS_DISPLAY1 = disp->display1.d;
GS_DISPFB2 = disp->dispfb2.d;
GS_DISPLAY2 = disp->display2.d;
GS_BGCOLOR = disp->bgcolor.d;
}
void
GsInitDrawCtx(GsDrawCtx *draw, int width, int height, int psm, int zpsm)
{
MAKE128(draw->gifTag, 0xe,
GIF_MAKE_TAG(8, 1, 0, 0, GIF_PACKED, 1));
draw->frame1.d = GS_MAKE_FRAME(0, width/64, psm, 0);
draw->ad_frame1 = GS_FRAME_1;
draw->frame2.d = draw->frame1.d;
draw->ad_frame2 = GS_FRAME_2;
draw->zbuf1.d = GS_MAKE_ZBUF(0, zpsm, 0);
draw->ad_zbuf1 = GS_ZBUF_1;
draw->zbuf2.d = draw->zbuf1.d;
draw->ad_zbuf2 = GS_ZBUF_2;
draw->xyoffset1.d = GS_MAKE_XYOFFSET(2048<<4, 2048<<4);
draw->ad_xyoffset1 = GS_XYOFFSET_1;
draw->xyoffset2.d = draw->xyoffset1.d;
draw->ad_xyoffset2 = GS_XYOFFSET_2;
draw->scissor1.d = GS_MAKE_SCISSOR(0, width-1, 0, height-1);
draw->ad_scissor1 = GS_SCISSOR_1;
draw->scissor2.d = draw->scissor1.d;
draw->ad_scissor2 = GS_SCISSOR_2;
}
void
GsPutDrawCtx(GsDrawCtx *draw)
{
// printquad(*(uint128*)&draw->frame1);
toGIF(draw, 9);
}
void
GsInitCtx(GsCtx *ctx, int width, int height, int psm, int zpsm)
{
uint fbsz, zbsz;
uint fbp, zbp;
fbsz = (width*height*psmsizemap[psm] + 2047)/2048;
zbsz = (width*height*psmsizemap[0x30|zpsm] + 2047)/2048;
gsAllocPtr = 2*fbsz + zbsz;
fbp = fbsz;
zbp = fbsz*2;
GsInitDispCtx(&ctx->disp[0], width, height, psm);
GsInitDispCtx(&ctx->disp[1], width, height, psm);
GsInitDrawCtx(&ctx->draw[0], width, height, psm, zpsm);
GsInitDrawCtx(&ctx->draw[1], width, height, psm, zpsm);
ctx->disp[1].dispfb2.f.FBP = fbp/4;
ctx->draw[0].frame1.f.FBP = fbp/4;
ctx->draw[0].frame2.f.FBP = fbp/4;
ctx->draw[0].zbuf1.f.ZBP = zbp/4;
ctx->draw[0].zbuf2.f.ZBP = zbp/4;
ctx->draw[1].zbuf1.f.ZBP = zbp/4;
ctx->draw[1].zbuf2.f.ZBP = zbp/4;
}
void
initrender(void)
{
uint128 *p, tmp;
p = packetbuf;
MAKE128(tmp, 0xe, GIF_MAKE_TAG(2, 1, 0, 0, GIF_PACKED, 1));
*p++ = tmp;
MAKE128(tmp, GS_PRMODECONT, 1);
*p++ = tmp;
MAKE128(tmp, GS_COLCLAMP, 1);
*p++ = tmp;
toGIF(packetbuf, 3);
}
void
clearscreen(int r, int g, int b)
{
int x, y;
uint128 *p, tmp;
p = packetbuf;
x = (2048 + WIDTH)<<4;
y = (2048 + HEIGHT)<<4;
MAKE128(tmp, 0xe, GIF_MAKE_TAG(5, 1, 0, 0, GIF_PACKED, 1));
*p++ = tmp;
MAKE128(tmp, GS_TEST_1, GS_MAKE_TEST(0, 0, 0, 0, 0, 0, 1, 1));
*p++ = tmp;
MAKE128(tmp, GS_PRIM, GS_MAKE_PRIM(GS_PRIM_SPRITE,0,0,0,0,0,0,0,0));
*p++ = tmp;
MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(r, g, b, 0, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(2048<<4, 2048<<4, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x, y, 0));
*p++ = tmp;
toGIF(packetbuf, 6);
}
void
drawtest(void)
{
int x0, x1, x2, x3;
int y0, y1, y2;
uint128 *p, tmp;
int n;
x0 = 2048<<4;
x1 = (2048 + 210)<<4;
x2 = (2048 + 430)<<4;
x3 = (2048 + 640)<<4;
y0 = 2048<<4;
y1 = (2048 + 224)<<4;
y2 = (2048 + 448)<<4;
n = 2 + 3*7;
p = packetbuf;
MAKEQ(tmp, 0x70000000 | n+1, 0, 0, 0);
*p++ = tmp;
MAKE128(tmp, 0xe, GIF_MAKE_TAG(n, 1, 0, 0, GIF_PACKED, 1));
*p++ = tmp;
MAKE128(tmp, GS_TEST_1, GS_MAKE_TEST(0, 0, 0, 0, 0, 0, 1, 1));
*p++ = tmp;
MAKE128(tmp, GS_PRIM, GS_MAKE_PRIM(GS_PRIM_SPRITE,0,0,0,0,0,0,0,0));
*p++ = tmp;
MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 0, 0, 0, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x0, y0, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y1, 0));
*p++ = tmp;
MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(0, 255, 0, 0, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y0, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y1, 0));
*p++ = tmp;
MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(0, 0, 255, 0, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y0, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x3, y1, 0));
*p++ = tmp;
MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(0, 255, 255, 0, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x0, y1, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y2, 0));
*p++ = tmp;
MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 0, 255, 0, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y1, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y2, 0));
*p++ = tmp;
MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 255, 0, 0, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y1, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x3, y2, 0));
*p++ = tmp;
MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 255, 255, 0, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ((2048+20)<<4, y0, 0));
*p++ = tmp;
MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x3, (2048+20)<<4, 0));
*p++ = tmp;
toGIFchain(packetbuf);
}
void
drawtri(void)
{
uint128 *p, tmp;
uint32 *ip;
int nverts, n;
nverts = 3;
n = 2*nverts;
p = packetbuf;
MAKEQ(tmp, 0x70000000 | n+1, 0, 0, 0);
*p++ = tmp;
MAKE128(tmp, (0x5<<4) | 0x1,
GIF_MAKE_TAG(nverts, 1, 1, GS_MAKE_PRIM(GS_PRIM_TRI, 1, 0, 0, 0, 0, 0, 0, 0), GIF_PACKED, 2));
*p++ = tmp;
MAKEQ(tmp, 255, 0, 0, 0);
*p++ = tmp;
MAKEQ(tmp, (2048+85)<<4, (2048+70)<<4, 0, 0);
*p++ = tmp;
MAKEQ(tmp, 0, 255, 0, 0);
*p++ = tmp;
MAKEQ(tmp, (2048+260)<<4, (2048+200)<<4, 0, 0);
*p++ = tmp;
MAKEQ(tmp, 0, 0, 255, 0);
*p++ = tmp;
MAKEQ(tmp, (2048+180)<<4, (2048+350)<<4, 0, 0);
*p++ = tmp;
toGIFchain(packetbuf);
}
void
printMatrix(rw::Matrix *m)
{
rw::V3d *x = &m->right;
rw::V3d *y = &m->up;
rw::V3d *z = &m->at;
rw::V3d *w = &m->pos;
printf(
"[ [ %8.4f, %8.4f, %8.4f, %8.4f ]\n"
" [ %8.4f, %8.4f, %8.4f, %8.4f ]\n"
" [ %8.4f, %8.4f, %8.4f, %8.4f ]\n"
" [ %8.4f, %8.4f, %8.4f, %8.4f ] ]\n"
" %08x == flags\n",
x->x, y->x, z->x, w->x,
x->y, y->y, z->y, w->y,
x->z, y->z, z->z, w->z,
0.0f, 0.0f, 0.0f, 1.0f,
m->flags);
}
// This is not proper data, just for testing
void
setupLight(rw::Atomic *atomic)
{
using namespace rw;
Matrix *lightmat;
float32 *lp;
numLightQ = 0;
lp = (float32*)lightpacket;
// TODO: this is the wrong matrix. we actually want to
// transform the light, not all normals.
lightmat = atomic->getFrame()->getLTM();
*lp++ = lightmat->right.x;
*lp++ = lightmat->right.y;
*lp++ = lightmat->right.z;
*lp++ = 0.0f;
*lp++ = lightmat->up.x;
*lp++ = lightmat->up.y;
*lp++ = lightmat->up.z;
*lp++ = 0.0f;
*lp++ = lightmat->at.x;
*lp++ = lightmat->at.y;
*lp++ = lightmat->at.z;
*lp++ = 0.0f;
*lp++ = lightmat->pos.x;
*lp++ = lightmat->pos.y;
*lp++ = lightmat->pos.z;
*lp++ = 1.0f;
// TODO: make a proper light block
// ambient
*lp++ = 80.0f;
*lp++ = 80.0f;
*lp++ = 80.0f;
*lp++ = 0.0f;
// directional
*lp++ = 0.5f;
*lp++ = -0.5f;
*lp++ = -0.7071f;
*lp++ = 0.0f;
numLightQ = 6;
}
void
setupTransform(rw::Atomic *atomic, rw::Matrix *trans)
{
rw::Matrix::mult(trans, atomic->getFrame()->getLTM(), &camera->viewMatrix);
}
enum {
DMAcnt = 0x10000000,
DMAref = 0x30000000,
DMAcall = 0x50000000,
DMAret = 0x60000000,
DMAend = 0x70000000,
V4_32 = 0x6C
};
#define UNPACK(type, nq, offset) ((type)<<24 | (nq)<<16 | (offset))
#define STCYCL(WL,CL) (0x01000000 | (WL)<<8 | (CL))
void
drawAtomic(rw::Atomic *atomic)
{
using namespace rw;
Matrix trans;
Geometry *geo;
ps2::ObjPipeline *pipe;
ps2::MatPipeline *matpipe;
Material *material;
uint128 tmp, *lp;
uint32 *vec;
RGBAf color;
int i;
geo = atomic->geometry;
pipe = (ps2::ObjPipeline*)atomic->getPipeline();
if(pipe->platform != PLATFORM_PS2)
return;
setupLight(atomic);
setupTransform(atomic, &trans);
curVifPtr = packetbuf;
// upload lights
MAKEQ(tmp, DMAcnt | numLightQ+8, 0, STCYCL(4,4), UNPACK(V4_32, numLightQ, 0x3d0));
*curVifPtr++ = tmp;
for(lp = lightpacket; numLightQ--;)
*curVifPtr++ = *lp++;
// upload transformation matrix
MAKEQ(tmp, 0, 0, STCYCL(4,4), UNPACK(V4_32, 4, 0x3f0));
*curVifPtr++ = tmp;
vec = (uint32*)&trans.right;
MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]);
*curVifPtr++ = tmp;
vec = (uint32*)&trans.up;
MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]);
*curVifPtr++ = tmp;
vec = (uint32*)&trans.at;
MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]);
*curVifPtr++ = tmp;
vec = (uint32*)&trans.pos;
MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]);
*curVifPtr++ = tmp;
// upload camera/screen info
MAKEQ(tmp, 0, 0, STCYCL(4,4), UNPACK(V4_32, 2, 0x3f7));
*curVifPtr++ = tmp;
*curVifPtr++ = vuXYZScale;
*curVifPtr++ = vuXYZOffset;
assert(geo->instData != NULL);
rw::ps2::InstanceDataHeader *instData =
(rw::ps2::InstanceDataHeader*)geo->instData;
rw::MeshHeader *meshHeader = geo->meshHeader;
rw::Mesh *mesh;
for(i = 0; i < instData->numMeshes; i++){
material = instData->instanceMeshes[i].material;
matpipe = pipe->groupPipeline;
if(matpipe == nil)
matpipe = (ps2::MatPipeline*)material->pipeline;
if(matpipe == nil)
matpipe = ps2::defaultMatPipe;
// call vu code
MAKEQ(tmp, DMAcall, (uint32)skinPipe, 0, 0);
*curVifPtr++ = tmp;
// unpack GIF tag, material color, surface properties
MAKEQ(tmp, DMAcnt | 3, 0, STCYCL(4,4), UNPACK(V4_32, 3, 0x3fa));
*curVifPtr++ = tmp;
MAKE128(tmp, 0x412,
GIF_MAKE_TAG(0, 1, 1, GS_MAKE_PRIM(GS_PRIM_TRI_STRIP,1,0,0,0,0,0,0,0), GIF_PACKED, 3));
*curVifPtr++ = tmp;
convColor(&color, &material->color);
color.alpha *= 128.0f/255.0f;
MAKEQ(tmp, *(uint32*)&color.red, *(uint32*)&color.green,
*(uint32*)&color.blue, *(uint32*)&color.alpha);
*curVifPtr++ = tmp;
MAKEQ(tmp, *(uint32*)&material->surfaceProps.ambient,
*(uint32*)&material->surfaceProps.specular,
*(uint32*)&material->surfaceProps.diffuse,
0.0f); // extra
*curVifPtr++ = tmp;
// call geometry
MAKEQ(tmp, DMAcall, (uint32)instData->instanceMeshes[i].data, 0x03000000, 0x02000000 | matpipe->vifOffset);
*curVifPtr++ = tmp;
}
MAKEQ(tmp, DMAend, 0, 0, 0);
*curVifPtr++ = tmp;
// for(lp = packetbuf; lp < curVifPtr; lp++)
// printquad4(*lp);
toVIF1chain(packetbuf);
}
void
beginCamera(void)
{
uint128 *p, tmp;
float32 *f;
p = packetbuf;
MAKE128(tmp, 0xe, GIF_MAKE_TAG(2, 1, 0, 0, GIF_PACKED, 1));
*p++ = tmp;
MAKE128(tmp, GS_XYOFFSET_1, GS_MAKE_XYOFFSET(2048-WIDTH/2 <<4, 2048-HEIGHT/2 <<4));
*p++ = tmp;
MAKE128(tmp, GS_TEST_1, GS_MAKE_TEST(0, 0, 0, 0, 0, 0, 1, 2));
*p++ = tmp;
toGIF(packetbuf, 3);
f = (float32*)&vuXYZScale;
f[0] = WIDTH;
f[1] = HEIGHT;
f[2] = camera->zScale;
f[3] = 0.0f;
f = (float32*)&vuXYZOffset;
f[0] = 2048.0f;
f[1] = 2048.0f;
f[2] = camera->zShift;
f[3] = 0.0f;
}
rw::EngineOpenParams engineOpenParams;
void
pluginattach(void)
{
rw::ps2::registerPDSPlugin(40);
rw::ps2::registerPluginPDSPipes();
rw::registerMeshPlugin();
rw::registerNativeDataPlugin();
rw::registerAtomicRightsPlugin();
rw::registerMaterialRightsPlugin();
rw::xbox::registerVertexFormatPlugin();
rw::registerSkinPlugin();
rw::registerHAnimPlugin();
rw::registerMatFXPlugin();
rw::registerUVAnimPlugin();
rw::ps2::registerADCPlugin();
}
bool32
initrw(void)
{
rw::version = 0x34000;
rw::platform = rw::PLATFORM_PS2;
if(!rw::Engine::init())
return 0;
pluginattach();
if(!rw::Engine::open(&engineOpenParams))
return 0;
if(!rw::Engine::start())
return 0;
rw::Texture::setLoadTextures(0);
rw::TexDictionary::setCurrent(rw::TexDictionary::create());
rw::Image::setSearchPath(".");
world = rw::World::create();
camera = rw::Camera::create();
camera->frameBuffer = rw::Raster::create(WIDTH, HEIGHT, 0, rw::Raster::CAMERA);
camera->zBuffer = rw::Raster::create(WIDTH, HEIGHT, 0, rw::Raster::ZBUFFER);
camera->setFrame(rw::Frame::create());
rw::V3d t = { 0.0f, 0.0f, -4.0f };
// rw::V3d t = { 0.0f, 0.0f, -40.0f };
camera->getFrame()->translate(&t, rw::COMBINEPOSTCONCAT);
rw::V3d axis = { 0.0f, 1.0f, 0.0f };
camera->getFrame()->rotate(&axis, 40.0f, rw::COMBINEPOSTCONCAT);
camera->setNearPlane(0.1f);
camera->setFarPlane(450.0f);
camera->setFOV(60.0f, 4.0f/3.0f);
world->addCamera(camera);
return 1;
}
int vsynchInt = 0;
int
vsynch(int id)
{
vsynchInt = 1;
frames++;
ExitHandler();
return 0;
}
int
main()
{
FlushCache(0);
if(!initrw()){
printf("init failed!\n");
for(;;);
}
rw::uint32 len;
rw::uint8 *data = rw::getFileContents("host:player.DFF", &len);
// rw::uint8 *data = rw::getFileContents("host:od_newscafe_dy.dff", &len);
rw::StreamMemory in;
in.open(data, len);
rw::findChunk(&in, rw::ID_CLUMP, NULL, NULL);
rw::Clump *clump = rw::Clump::streamRead(&in);
in.close();
rwFree(data);
GsCtx gsCtx;
dmaReset();
// GsResetCrt(GS_NONINTERLACED, GS_NTSC, 0);
// GsInitCtx(&gsCtx, 640, 224, GS_PSMCT32, GS_PSMZ32);
// GsResetCrt(GS_INTERLACED, GS_NTSC, GS_FRAME);
// GsInitCtx(&gsCtx, 640, 224, GS_PSMCT32, GS_PSMZ32);
GsResetCrt(GS_INTERLACED, VMODE, GS_FIELD);
GsInitCtx(&gsCtx, WIDTH, HEIGHT, GS_PSMCT32, GS_PSMZ32);
initrender();
AddIntcHandler(2, vsynch, 0);
EnableIntc(2);
GsPutDrawCtx(&gsCtx.draw[0]);
GsPutDispCtx(&gsCtx.disp[1]);
// PCSX2 needs a delay for some reason
{ int i; for(i = 0; i < 1000000; i++); }
clearscreen(0x80, 0x80, 0x80);
// drawtest();
// drawtri();
float angle = 40.0f;
int drawbuf = 0;
int dispbuf = 1;
for(;;){
clearscreen(0x80, 0x80, 0x80);
rw::V3d t = { 0.0f, 0.0f, -4.0f };
camera->getFrame()->translate(&t, rw::COMBINEREPLACE);
rw::V3d axis = { 0.0f, 1.0f, 0.0f };
camera->getFrame()->rotate(&axis, angle, rw::COMBINEPOSTCONCAT);
angle += 1.0f;
camera->beginUpdate();
beginCamera();
FORLIST(lnk, clump->atomics)
drawAtomic(rw::Atomic::fromClump(lnk));
camera->endUpdate();
printf("");
while(vsynchInt == 0);
GsPutDrawCtx(&gsCtx.draw[drawbuf]);
GsPutDispCtx(&gsCtx.disp[dispbuf]);
drawbuf = !drawbuf;
dispbuf = !dispbuf;
vsynchInt = 0;
}
/*
camera->beginUpdate();
beginCamera();
FORLIST(lnk, clump->atomics)
drawAtomic(rw::Atomic::fromClump(lnk));
camera->endUpdate();
printf("hello %p\n", clump);
for(;;)
printf("");
*/
return 0;
}
+95
View File
@@ -0,0 +1,95 @@
/* FIFOs */
#define VIF0_FIFO (*(volatile uint128*)0x10004000)
#define VIF1_FIFO (*(volatile uint128*)0x10005000)
#define GIF_FIFO (*(volatile uint128*)0x10006000)
#define IPU_out_FIFO (*(volatile uint128*)0x10007000)
#define IPU_in_FIFO (*(volatile uint128*)0x10007010)
/* DMA channels */
// to VIF0
#define D0_CHCR (*(volatile uint32*)0x10008000)
#define D0_MADR (*(volatile uint32*)0x10008010)
#define D0_QWC (*(volatile uint32*)0x10008020)
#define D0_TADR (*(volatile uint32*)0x10008030)
#define D0_ASR0 (*(volatile uint32*)0x10008040)
#define D0_ASR1 (*(volatile uint32*)0x10008050)
// VIF1
#define D1_CHCR (*(volatile uint32*)0x10009000)
#define D1_MADR (*(volatile uint32*)0x10009010)
#define D1_QWC (*(volatile uint32*)0x10009020)
#define D1_TADR (*(volatile uint32*)0x10009030)
#define D1_ASR0 (*(volatile uint32*)0x10009040)
#define D1_ASR1 (*(volatile uint32*)0x10009050)
// to GIF
#define D2_CHCR (*(volatile uint32*)0x1000a000)
#define D2_MADR (*(volatile uint32*)0x1000a010)
#define D2_QWC (*(volatile uint32*)0x1000a020)
#define D2_TADR (*(volatile uint32*)0x1000a030)
#define D2_ASR0 (*(volatile uint32*)0x1000a040)
#define D2_ASR1 (*(volatile uint32*)0x1000a050)
// fromIPU
#define D3_CHCR (*(volatile uint32*)0x1000b000)
#define D3_MADR (*(volatile uint32*)0x1000b010)
#define D3_QWC (*(volatile uint32*)0x1000b020)
// toIPU
#define D4_CHCR (*(volatile uint32*)0x1000b400)
#define D4_MADR (*(volatile uint32*)0x1000b410)
#define D4_QWC (*(volatile uint32*)0x1000b420)
#define D4_TADR (*(volatile uint32*)0x1000b430)
// from SIF0
#define D5_CHCR (*(volatile uint32*)0x1000c000)
#define D5_MADR (*(volatile uint32*)0x1000c010)
#define D5_QWC (*(volatile uint32*)0x1000c020)
// to SIF1
#define D6_CHCR (*(volatile uint32*)0x1000c400)
#define D6_MADR (*(volatile uint32*)0x1000c410)
#define D6_QWC (*(volatile uint32*)0x1000c420)
#define D6_TADR (*(volatile uint32*)0x1000c430)
// SIF2
#define D7_CHCR (*(volatile uint32*)0x1000c800)
#define D7_MADR (*(volatile uint32*)0x1000c810)
#define D7_QWC (*(volatile uint32*)0x1000c820)
// fromSPR
#define D8_CHCR (*(volatile uint32*)0x1000d000)
#define D8_MADR (*(volatile uint32*)0x1000d010)
#define D8_QWC (*(volatile uint32*)0x1000d020)
#define D8_SADR (*(volatile uint32*)0x1000d080)
// toSPR
#define D9_CHCR (*(volatile uint32*)0x1000d400)
#define D9_MADR (*(volatile uint32*)0x1000d410)
#define D9_QWC (*(volatile uint32*)0x1000d420)
#define D9_TADR (*(volatile uint32*)0x1000d430)
#define D9_SADR (*(volatile uint32*)0x1000d480)
/* DMA controller */
#define D_CTRL (*(volatile uint32*)0x1000e000)
#define D_STAT (*(volatile uint32*)0x1000e010)
#define D_PCR (*(volatile uint32*)0x1000e020)
#define D_SQWC (*(volatile uint32*)0x1000e030)
#define D_RBSR (*(volatile uint32*)0x1000e040)
#define D_RBOR (*(volatile uint32*)0x1000e050)
#define D_STADR (*(volatile uint32*)0x1000e060)
#define D_ENABLER (*(volatile uint32*)0x1000f520)
#define D_ENABLEW (*(volatile uint32*)0x1000f590)
/* GS privileged registers */
#define GS_PMODE (*(volatile uint64*)0x12000000)
#define GS_SMODE1 (*(volatile uint64*)0x12000010)
#define GS_SMODE2 (*(volatile uint64*)0x12000020)
#define GS_SRFSH (*(volatile uint64*)0x12000030)
#define GS_SYNCH1 (*(volatile uint64*)0x12000040)
#define GS_SYNCH2 (*(volatile uint64*)0x12000050)
#define GS_SYNCV (*(volatile uint64*)0x12000060)
#define GS_DISPFB1 (*(volatile uint64*)0x12000070)
#define GS_DISPLAY1 (*(volatile uint64*)0x12000080)
#define GS_DISPFB2 (*(volatile uint64*)0x12000090)
#define GS_DISPLAY2 (*(volatile uint64*)0x120000a0)
#define GS_EXTBUF (*(volatile uint64*)0x120000b0)
#define GS_EXTDATA (*(volatile uint64*)0x120000c0)
#define GS_EXTWRITE (*(volatile uint64*)0x120000d0)
#define GS_BGCOLOR (*(volatile uint64*)0x120000e0)
#define GS_CSR (*(volatile uint64*)0x12001000)
#define GS_IMR (*(volatile uint64*)0x12001010)
#define GS_BUSDIR (*(volatile uint64*)0x12001040)
#define GS_SIGLBLID (*(volatile uint64*)0x12001080)
+23
View File
@@ -0,0 +1,23 @@
#include <kernel.h>
typedef int quad __attribute__((mode(TI)));
typedef int int128 __attribute__((mode(TI)));
typedef unsigned int uquad __attribute__((mode(TI)));
typedef unsigned int uint128 __attribute__((mode(TI)));
#define MAKE128(RES,MSB,LSB) \
__asm__ ( "pcpyld %0, %1, %2" : "=r" (RES) : "r" ((uint64)MSB), "r" ((uint64)LSB))
#define UINT64(LOW,HIGH) (((uint64)HIGH)<<32 | ((uint64)LOW))
#define MAKEQ(RES,W0,W1,W2,W3) MAKE128(RES,UINT64(W2,W3),UINT64(W0,W1))
#define BIT64(v,s) (((uint64)(v)) << (s))
#include "mem.h"
#include "gs.h"
extern uint128 packetbuf[128];
void waitDMA(volatile uint32 *chcr);
void toGIF(void *src, int n);
void drawcube(void);
+93
View File
@@ -0,0 +1,93 @@
.global defaultPipe
.equ vertexTop, 0x3d0
.equ numInAttribs, 4
.equ numOutAttribs, 3
.equ numOutBuf, 2
.equ vertCount, ((vertexTop-numOutBuf)/(numInAttribs*2+numOutAttribs*numOutBuf))
.equ offset, (vertCount*numInAttribs)
.equ outBuf1, (2*offset)
.equ outSize, ((vertexTop-outBuf1-2)/2)
.equ outBuf2, (outBuf1+outSize)
.equ lightMat, 0x3d0
.equ ambientLight, 0x3d4
.equ lightDir, 0x3d5
.equ matrix, 0x3f0
.equ XYZScale, 0x3f7
.equ XYZOffset, 0x3f8
.equ gifTag, 0x3fa
.equ matColor, 0x3fb
.equ surfProps, 0x3fc
.balign 16,0
defaultPipe:
DMAret *
MPG 0, *
.vu
Start:
#include "setup_persp.vu"
Cnt:
NOP XTOP VI02 ; input pointer
NOP LQ VF01, gifTag(VI00)
NOP XITOP VI01 ; vertex count
NOP IADDIU VI05, VI00, 0x4000
NOP IADD VI05, VI05, VI05
NOP IOR VI05, VI05, VI01
NOP SQ VF01, 0(VI12)
NOP ISW.x VI05, 0(VI12)
NOP IADDIU VI03, VI12, 1 ; output pointer
NOP LQ VF18, lightMat(VI00)
NOP LQ VF19, lightMat+1(VI00)
NOP LQ VF20, lightMat+2(VI00)
Loop:
NOP LQI VF01, (VI02++) ; vertex
NOP LQI VF02, (VI02++) ; UV
NOP LQI VF03, (VI02++) ; color
NOP LQI VF04, (VI02++) ; normal
MULAw.xyzw ACC, VF31, VF00w NOP ; transform vertex
MADDAx.xyw ACC, VF28, VF01x NOP
MADDAy.xyw ACC, VF29, VF01y NOP
MADDz.xyzw VF01, VF30, VF01z NOP
ITOF0 VF03, VF03 NOP
ITOF0[I] VF04, VF04 LOI 0.0078125 ; - normal scale
NOP NOP
NOP DIV Q, VF00w, VF01w
NOP WAITQ
MULq VF01, VF01, Q NOP ; perspective division
MULi VF04, VF04, I NOP ; scale normal
NOP MR32.z VF02, VF00
NOP NOP
SUB.w VF01, VF01, VF01 NOP
MULAx.xyz ACC, VF18, VF04x NOP ; transform normal
MADDAy.xyz ACC, VF19, VF04y NOP
MADDz.xyz VF04, VF20, VF04z NOP
ADD.xyz VF01, VF01, VF25 NOP
MULq VF02, VF02, Q NOP
NOP NOP
FTOI0 VF03, VF03 NOP
FTOI4 VF01, VF01 NOP
NOP SQ VF04, -2(VI02) ; store normal
NOP IADDI VI01, VI01, -1
NOP SQI VF02, (VI03++) ; STQ
NOP SQI VF03, (VI03++) ; color
NOP SQI VF01, (VI03++) ; vertex
NOP IBNE VI01, VI00, Loop
NOP NOP
#include "light.vu"
NOP XGKICK VI12
NOP IADD VI15,VI00,VI12
NOP IADD VI12,VI00,VI13
NOP[E] IADD VI13,VI00,VI15
NOP NOP
NOP B Cnt
NOP NOP
.EndMPG
.EndDmaData
+94
View File
@@ -0,0 +1,94 @@
; Ambient light:
NOP LQ VF26, ambientLight(VI00)
NOP XITOP VI01
NOP IADDIU VI03, VI12, 2
Ambloop:
NOP LQ VF03, 0(VI03) ; output color
NOP NOP
NOP NOP
NOP NOP
ITOF0 VF03, VF03 NOP
NOP NOP
NOP NOP
NOP NOP
ADD.xyz VF03, VF03, VF26 NOP
NOP NOP
NOP NOP
NOP NOP
FTOI0 VF03, VF03 NOP
NOP IADDI VI01, VI01, -1
NOP IADDIU VI03, VI03, numOutAttribs
NOP IBNE VI01, VI00, Ambloop
NOP SQ VF03, -numOutAttribs(VI03)
; end amblight
; Direct Light
NOP LQ VF26, lightDir(VI00)
NOP XITOP VI01
NOP XTOP VI02
NOP IADDIU VI03, VI12, 2
SUB.xyz VF26, VF00, VF26 NOP
Dirloop:
NOP LQ VF01, 3(VI02); ; normal
NOP LQ VF02, 0(VI03); ; output color
NOP NOP
NOP NOP
MUL VF03, VF01, VF26 NOP
ITOF0 VF02, VF02 NOP
NOP NOP
NOP NOP
ADDy.x VF03, VF03, VF03y NOP
NOP NOP
NOP NOP
NOP NOP
ADDz.x VF03, VF03, VF03z NOP
NOP NOP
NOP NOP
NOP NOP
MAX.x VF03, VF00, VF03 NOP ; clamp to 0
NOP[I] LOI 255
NOP NOP
NOP NOP
MULi.x VF03, VF03, I NOP
NOP NOP
NOP NOP
NOP NOP
ADDx.xyz VF02, VF02, VF03x NOP
NOP NOP
NOP NOP
NOP NOP
FTOI0 VF02, VF02 NOP
NOP IADDI VI01, VI01, -1
NOP IADDIU VI02, VI02, numInAttribs
NOP IADDIU VI03, VI03, numOutAttribs
NOP IBNE VI01, VI00, Dirloop
NOP SQ VF02, -numOutAttribs(VI03)
; end dirlight
; Material color and clamp
NOP LQ VF27, matColor(VI00)
NOP XITOP VI01
NOP IADDIU VI03, VI12, 2
Colorloop:
NOP LQ VF03, 0(VI03)
NOP NOP
NOP NOP
NOP NOP
ITOF0 VF03, VF03 NOP
NOP NOP
NOP NOP
NOP NOP
MUL VF03, VF03, VF27 NOP
NOP[I] LOI 255
NOP NOP
NOP NOP
MINIi VF03, VF03, I NOP
NOP NOP
NOP NOP
NOP NOP
FTOI0 VF03, VF03 NOP
NOP IADDI VI01, VI01, -1
NOP IADDIU VI03, VI03, numOutAttribs
NOP IBNE VI01, VI00, Colorloop
NOP SQ VF03, -numOutAttribs(VI03)
; end material color
+39
View File
@@ -0,0 +1,39 @@
/* This is the the projection matrix we start with:
* 1/2w 0 ox/2w + 1/2 -ox/2w
* 0 -1/2h -oy/2h + 1/2 oy/2h
* 0 0 1 0
* 0 0 1 0
* To get rid of the +1/2 in the combined matrix we
* subtract the z-row/2 from the x- and y-rows.
*
* The z-row is then set to [0 0 0 1] such that multiplication
* by XYZscale gives [0 0 0 zScale]. After perspective division
* and addition of XYZoffset we then get zScale/w + zShift for z.
*
* XYZScale scales xy to the resolution and z by zScale.
* XYZOffset translates xy to the GS coordinate system (where
* [2048, 2048] is the center of the frame buffer) and add zShift to z.
*/
; constant:
; VF28-VF31 transformation matrix
; VF25 XYZ offset
SUB.z VF28, VF28, VF28 LOI 0.5 ; right.z = 0
SUB.z VF29, VF29, VF29 LQ VF28, matrix(VI00) ; up.z = 0 - load matrix
SUB.z VF30, VF30, VF30 LQ VF29, matrix+1(VI00) ; at.z = 0 - load matrix
ADDw.z VF31, VF00, VF00 LQ VF30, matrix+2(VI00) ; at.z = 1 - load matrix
NOP LQ VF31, matrix+3(VI00) ; - load matrix
MULi.w VF20, VF28, I LQ.xyz VF01, XYZScale(VI00) ; fix matrix - load scale
MULi.w VF21, VF29, I NOP ; fix matrix
MULi.w VF22, VF30, I NOP ; fix matrix
MULi.w VF23, VF31, I NOP ; fix matrix
SUBw.xy VF28, VF28, VF20 NOP ; fix matrix
SUBw.xy VF29, VF29, VF21 NOP ; fix matrix
SUBw.xy VF30, VF30, VF22 NOP ; fix matrix
SUBw.xy VF31, VF31, VF23 NOP ; fix matrix
MUL.xy VF28, VF28, VF01 LQ.xyz VF25, XYZOffset(VI00) ; scale matrix
MUL.xy VF29, VF29, VF01 IADDIU VI12, VI00, outBuf1 ; scale matrix
MUL.xy VF30, VF30, VF01 IADDIU VI13, VI00, outBuf2 ; scale matrix
MUL.xyz VF31, VF31, VF01 NOP ; scale matrix
+94
View File
@@ -0,0 +1,94 @@
.global skinPipe
.equ vertexTop, 0x2d0
.equ numInAttribs, 5
.equ numOutAttribs, 3
.equ numOutBuf, 2
.equ vertCount, ((vertexTop-numOutBuf)/(numInAttribs*2+numOutAttribs*numOutBuf))
.equ offset, (vertCount*numInAttribs)
.equ outBuf1, (2*offset)
.equ outSize, ((vertexTop-outBuf1-2)/2)
.equ outBuf2, (outBuf1+outSize)
.equ lightMat, 0x3d0
.equ ambientLight, 0x3d4
.equ lightDir, 0x3d5
.equ matrix, 0x3f0
.equ XYZScale, 0x3f7
.equ XYZOffset, 0x3f8
.equ gifTag, 0x3fa
.equ matColor, 0x3fb
.equ surfProps, 0x3fc
.balign 16,0
skinPipe:
DMAret *
MPG 0, *
.vu
Start:
#include "setup_persp.vu"
Cnt:
NOP XTOP VI02 ; input pointer
NOP LQ VF01, gifTag(VI00)
NOP XITOP VI01 ; vertex count
NOP IADDIU VI05, VI00, 0x4000
NOP IADD VI05, VI05, VI05
NOP IOR VI05, VI05, VI01
NOP SQ VF01, 0(VI12)
NOP ISW.x VI05, 0(VI12)
NOP IADDIU VI03, VI12, 1 ; output pointer
NOP LQ VF18, lightMat(VI00)
NOP LQ VF19, lightMat+1(VI00)
NOP LQ VF20, lightMat+2(VI00)
Loop:
NOP LQI VF01, (VI02++) ; vertex
NOP LQI VF02, (VI02++) ; UV
NOP LQI VF03, (VI02++) ; color
NOP LQI VF04, (VI02++) ; normal
NOP IADDIU VI02, VI02, 1 ; skip weights
MULAw.xyzw ACC, VF31, VF00w NOP ; transform vertex
MADDAx.xyw ACC, VF28, VF01x NOP
MADDAy.xyw ACC, VF29, VF01y NOP
MADDz.xyzw VF01, VF30, VF01z NOP
ITOF0 VF03, VF03 NOP
ITOF0[I] VF04, VF04 LOI 0.0078125 ; - normal scale
NOP NOP
NOP DIV Q, VF00w, VF01w
NOP WAITQ
MULq VF01, VF01, Q NOP ; perspective division
MULi VF04, VF04, I NOP ; scale normal
NOP MR32.z VF02, VF00
NOP NOP
SUB.w VF01, VF01, VF01 NOP
MULAx.xyz ACC, VF18, VF04x NOP ; transform normal
MADDAy.xyz ACC, VF19, VF04y NOP
MADDz.xyz VF04, VF20, VF04z NOP
ADD.xyz VF01, VF01, VF25 NOP
MULq VF02, VF02, Q NOP
NOP NOP
FTOI0 VF03, VF03 NOP
FTOI4 VF01, VF01 NOP
NOP SQ VF04, -2(VI02) ; store normal
NOP IADDI VI01, VI01, -1
NOP SQI VF02, (VI03++) ; STQ
NOP SQI VF03, (VI03++) ; color
NOP SQI VF01, (VI03++) ; vertex
NOP IBNE VI01, VI00, Loop
NOP NOP
#include "light.vu"
NOP XGKICK VI12
NOP IADD VI15,VI00,VI12
NOP IADD VI12,VI00,VI13
NOP[E] IADD VI13,VI00,VI15
NOP NOP
NOP B Cnt
NOP NOP
.EndMPG
.EndDmaData
+83
View File
@@ -0,0 +1,83 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <rw.h>
#include <args.h>
using namespace rw;
char *argv0;
void
usage(void)
{
fprintf(stderr, "usage: %s in.ska [out.anm]\n", argv0);
fprintf(stderr, " or: %s in.anm [out.ska]\n", argv0);
exit(1);
}
int
main(int argc, char *argv[])
{
rw::Engine::init();
rw::registerHAnimPlugin();
rw::Engine::open(nil);
rw::Engine::start();
ARGBEGIN{
case 'v':
sscanf(EARGF(usage()), "%x", &rw::version);
break;
default:
usage();
}ARGEND;
if(argc < 1)
usage();
StreamFile stream;
if(!stream.open(argv[0], "rb")){
fprintf(stderr, "Error: couldn't open %s\n", argv[0]);
return 1;
}
int32 firstword = stream.readU32();
stream.seek(0, 0);
Animation *anim = nil;
if(firstword == ID_ANIMANIMATION){
// it's an anm file
if(findChunk(&stream, ID_ANIMANIMATION, nil, nil))
anim = Animation::streamRead(&stream);
}else{
// it's a ska file
anim = Animation::streamReadLegacy(&stream);
}
stream.close();
if(anim == nil){
fprintf(stderr, "Error: couldn't read anim file\n");
return 1;
}
const char *file;
if(argc > 1)
file = argv[1];
else if(firstword == ID_ANIMANIMATION)
file = "out.ska";
else
file = "out.anm";
if(!stream.open(file, "wb")){
fprintf(stderr, "Error: couldn't open %s\n", file);
return 1;
}
if(firstword == ID_ANIMANIMATION)
anim->streamWriteLegacy(&stream);
else
anim->streamWrite(&stream);
anim->destroy();
return 0;
}