#include #include #include "subrast.h" rw::Camera *Camera; rw::Camera *SubCameras[4]; void CameraSetViewWindow(rw::Camera *camera, float width, float height, float vw) { rw::V2d viewWindow; // TODO: aspect ratio when fullscreen if(width > height){ viewWindow.x = vw; viewWindow.y = vw / (width/height); }else{ viewWindow.x = vw / (height/width); viewWindow.y = vw; } camera->setViewWindow(&viewWindow); } void UpdateSubRasters(rw::Camera *mainCamera, rw::int32 mainWidth, rw::int32 mainHeight) { rw::Rect rect[4]; float width, height, border; border = mainHeight*0.05f; width = (mainWidth - border*3.0f) / 2.0f; height = (mainHeight - border*3.0f) / 2.0f; // top left rect[0].x = border; rect[0].y = border; rect[0].w = width; rect[0].h = height; // top right rect[1].x = border*2 + width; rect[1].y = border; rect[1].w = width; rect[1].h = height; // bottom left rect[2].x = border; rect[2].y = border*2 + height; rect[2].w = width; rect[2].h = height; // bottom left rect[3].x = border*2 + width; rect[3].y = border*2 + height; rect[3].w = width; rect[3].h = height; CameraSetViewWindow(SubCameras[0], width, height, 0.5f); for(int i = 1; i < 4; i++) CameraSetViewWindow(SubCameras[i], width, height, 0.5f + 0.4f); for(int i = 0; i < 4; i++){ SubCameras[i]->frameBuffer->subRaster(mainCamera->frameBuffer, &rect[i]); SubCameras[i]->zBuffer->subRaster(mainCamera->zBuffer, &rect[i]); } } void PositionSubCameras(void) { rw::Frame *frame; rw::V3d pos; const float dist = 2.5f; // perspective pos.x = pos.y = 0.0f; pos.z = -4.0f; frame = SubCameras[0]->getFrame(); frame->translate(&pos, rw::COMBINEREPLACE); // look along z pos.x = pos.y = 0.0f; pos.z = -dist; frame = SubCameras[1]->getFrame(); frame->translate(&pos, rw::COMBINEREPLACE); // look along x pos.x = -dist; pos.y = pos.z = 0.0f; frame = SubCameras[2]->getFrame(); frame->rotate(&Yaxis, 90.0f, rw::COMBINEREPLACE); frame->translate(&pos, rw::COMBINEPOSTCONCAT); // look along y pos.x = pos.z = 0.0f; pos.y = -dist; frame = SubCameras[3]->getFrame(); frame->rotate(&Xaxis, -90.0f, rw::COMBINEREPLACE); frame->translate(&pos, rw::COMBINEPOSTCONCAT); } void CreateCameras(rw::World *world) { Camera = sk::CameraCreate(sk::globals.width, sk::globals.height, 1); assert(Camera); for(int i = 0; i < 4; i++){ SubCameras[i] = sk::CameraCreate(0, 0, 1); assert(SubCameras[i]); SubCameras[i]->setNearPlane(0.1f); SubCameras[i]->setFarPlane(30.0f); world->addCamera(SubCameras[i]); if(i > 0) SubCameras[i]->setProjection(rw::Camera::PARALLEL); } PositionSubCameras(); } void DestroyCameras(rw::World *world) { } /* 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::RGBAf LightColor = { 1.0f, 1.0f, 1.0f, 1.0f }; rw::RGBA LightSolidColor = { 255, 255, 0, 255 }; bool LightOn = true; bool LightDrawOn = true; rw::V3d LightPos = {0.0f, 0.0f, 75.0f}; rw::int32 LightTypeIndex = 1; rw::BBox RoomBBox; 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; } void DestroyLight(rw::Light **light) { if(*light == nil) return; rw::World *world = (*light)->world; if(world) world->removeLight(*light); rw::Frame *frame = (*light)->getFrame(); if(frame){ (*light)->setFrame(nil); frame->destroy(); } (*light)->destroy(); *light = nil; } void LightsDestroy(void) { DestroyLight(&SpotSoftLight); DestroyLight(&SpotLight); DestroyLight(&PointLight); DestroyLight(&DirectLight); DestroyLight(&AmbientLight); DestroyLight(&BaseAmbientLight); } void LightsUpdate(void) { static rw::int32 oldLightTypeIndex = -1; // Switch to a different light if((LightOn && oldLightTypeIndex != LightTypeIndex) || CurrentLight == nil){ oldLightTypeIndex = LightTypeIndex; // remove first if(CurrentLight) CurrentLight->world->removeLight(CurrentLight); switch(LightTypeIndex){ case 0: CurrentLight = AmbientLight; break; case 1: CurrentLight = PointLight; break; case 2: CurrentLight = DirectLight; break; case 3: CurrentLight = SpotLight; break; case 4: CurrentLight = SpotSoftLight; break; } World->addLight(CurrentLight); } if(CurrentLight){ CurrentLight->setColor(LightColor.red, LightColor.green, LightColor.blue); CurrentLight->radius = LightRadius; CurrentLight->setAngle(LightConeAngle / 180.0f * M_PI); } // Remove light from world if not used if(!LightOn && CurrentLight){ CurrentLight->world->removeLight(CurrentLight); CurrentLight = nil; } } #define POINT_LIGHT_RADIUS_FACTOR 0.05f void DrawPointLight(void) { enum { NUMVERTS = 50 }; rw::RWDEVICE::Im3DVertex shape[NUMVERTS]; rw::int32 i; rw::V3d point; rw::V3d *pos = &CurrentLight->getFrame()->getLTM()->pos; for(i = 0; i < NUMVERTS; i++){ point.x = pos->x + cosf(i/(NUMVERTS/2.0f) * M_PI) * LightRadius * POINT_LIGHT_RADIUS_FACTOR; point.y = pos->y + sinf(i/(NUMVERTS/2.0f) * M_PI) * LightRadius * POINT_LIGHT_RADIUS_FACTOR; point.z = pos->z; shape[i].setColor(LightSolidColor.red, LightSolidColor.green, LightSolidColor.blue, LightSolidColor.alpha); shape[i].setX(point.x); shape[i].setY(point.y); shape[i].setZ(point.z); } rw::im3d::Transform(shape, NUMVERTS, nil, rw::im3d::ALLOPAQUE); rw::im3d::RenderPrimitive(rw::PRIMTYPEPOLYLINE); rw::im3d::RenderLine(NUMVERTS-1, 0); rw::im3d::End(); } void DrawCone(float coneAngle, float coneSize, float coneRatio) { enum { NUMVERTS = 10 }; rw::RWDEVICE::Im3DVertex shape[NUMVERTS+1]; rw::int16 indices[NUMVERTS*3]; rw::int32 i; rw::Matrix *matrix = CurrentLight->getFrame()->getLTM(); rw::V3d *pos = &matrix->pos; // cone for(i = 1; i < NUMVERTS+1; i++){ float cosValue = cosf(i/(NUMVERTS/2.0f) * M_PI) * sinf(coneAngle/180.0f*M_PI); float sinValue = sinf(i/(NUMVERTS/2.0f) * M_PI) * sinf(coneAngle/180.0f*M_PI); float coneAngleD = cosf(coneAngle/180.0f*M_PI); rw::V3d up = rw::scale(matrix->up, sinValue*coneSize); rw::V3d right = rw::scale(matrix->right, cosValue*coneSize); rw::V3d at = rw::scale(matrix->at, coneAngleD*coneSize*coneRatio); shape[i].setX(pos->x + at.x + up.x + right.x); shape[i].setY(pos->y + at.y + up.y + right.y); shape[i].setZ(pos->z + at.z + up.z + right.z); } for(i = 0; i < NUMVERTS; i++){ indices[i*3 + 0] = 0; indices[i*3 + 1] = i+2; indices[i*3 + 2] = i+1; } indices[NUMVERTS*3-2] = 1; for(i = 0; i < NUMVERTS+1; i++) shape[i].setColor(LightSolidColor.red, LightSolidColor.green, LightSolidColor.blue, 128); shape[0].setX(pos->x); shape[0].setY(pos->y); shape[0].setZ(pos->z); rw::SetRenderState(rw::VERTEXALPHA, 1); rw::SetRenderState(rw::SRCBLEND, rw::BLENDSRCALPHA); rw::SetRenderState(rw::DESTBLEND, rw::BLENDINVSRCALPHA); rw::im3d::Transform(shape, NUMVERTS+1, nil, 0); rw::im3d::RenderPrimitive(rw::PRIMTYPETRIFAN); rw::im3d::RenderTriangle(0, NUMVERTS, 1); rw::im3d::RenderIndexedPrimitive(rw::PRIMTYPETRILIST, indices, NUMVERTS*3); rw::im3d::End(); for(i = 0; i < NUMVERTS+1; i++) shape[i].setColor(LightSolidColor.red, LightSolidColor.green, LightSolidColor.blue, 255); float coneAngleD = cosf(coneAngle/180.0f*M_PI); rw::V3d at = rw::scale(matrix->at, coneAngleD*coneSize*coneRatio); shape[0].setX(pos->x + at.x); shape[0].setY(pos->y + at.y); shape[0].setZ(pos->z + at.z); rw::im3d::Transform(shape, NUMVERTS+1, nil, rw::im3d::ALLOPAQUE); if(coneRatio > 0.0f){ rw::im3d::RenderPrimitive(rw::PRIMTYPETRIFAN); rw::im3d::RenderTriangle(0, NUMVERTS, 1); }else rw::im3d::RenderIndexedPrimitive(rw::PRIMTYPETRIFAN, indices, NUMVERTS*3); rw::im3d::End(); // lines at = rw::scale(matrix->at, -0.05f); shape[0].setX(pos->x + at.x); shape[0].setY(pos->y + at.y); shape[0].setZ(pos->z + at.z); rw::im3d::Transform(shape, NUMVERTS+1, nil, rw::im3d::ALLOPAQUE); rw::im3d::RenderIndexedPrimitive(rw::PRIMTYPEPOLYLINE, indices, NUMVERTS*3); rw::im3d::End(); } void DrawDirectLight(void) { enum { NUMVERTS = 20 }; const float DIAMETER = 1.5f; const float CONE_ANGLE = 45.0f; const float CONE_SIZE = 3.0f; const float LENGTH = 5.0f; rw::RWDEVICE::Im3DVertex shape[NUMVERTS*2+1]; rw::int16 indices[NUMVERTS*3]; rw::int32 i; rw::Matrix *matrix = CurrentLight->getFrame()->getLTM(); rw::V3d *pos = &matrix->pos; // cylinder for(i = 0; i < NUMVERTS*2; i += 2){ float cosValue = cosf(i/(NUMVERTS/2.0f) * M_PI); float sinValue = sinf(i/(NUMVERTS/2.0f) * M_PI); rw::V3d up = rw::scale(matrix->up, sinValue*DIAMETER); rw::V3d right = rw::scale(matrix->right, cosValue*DIAMETER); rw::V3d at = rw::scale(matrix->at, -(CONE_SIZE + 1.0f)); shape[i].setX(pos->x + at.x + up.x + right.x); shape[i].setY(pos->y + at.y + up.y + right.y); shape[i].setZ(pos->z + at.z + up.z + right.z); at = rw::scale(matrix->at, -(LENGTH + CONE_SIZE)); shape[i+1].setX(pos->x + at.x + up.x + right.x); shape[i+1].setY(pos->y + at.y + up.y + right.y); shape[i+1].setZ(pos->z + at.z + up.z + right.z); } for(i = 0; i < NUMVERTS*2+1; i++) shape[i].setColor(LightSolidColor.red, LightSolidColor.green, LightSolidColor.blue, 128); rw::SetRenderState(rw::VERTEXALPHA, 1); rw::SetRenderState(rw::SRCBLEND, rw::BLENDSRCALPHA); rw::SetRenderState(rw::DESTBLEND, rw::BLENDINVSRCALPHA); rw::im3d::Transform(shape, NUMVERTS*2, nil, 0); rw::im3d::RenderPrimitive(rw::PRIMTYPETRISTRIP); rw::im3d::RenderTriangle(2*NUMVERTS-2, 2*NUMVERTS-1, 0); rw::im3d::RenderTriangle(2*NUMVERTS-1, 1, 0); rw::im3d::End(); // bottom cap for(i = 0; i < NUMVERTS*2+1; i++) shape[i].setColor(LightSolidColor.red, LightSolidColor.green, LightSolidColor.blue, 255); rw::V3d at = rw::scale(matrix->at, -(LENGTH + CONE_SIZE)); shape[NUMVERTS*2].setX(pos->x + at.x); shape[NUMVERTS*2].setY(pos->y + at.y); shape[NUMVERTS*2].setZ(pos->z + at.z); for(i = 0; i < NUMVERTS; i++){ indices[i*3+0] = NUMVERTS*2; indices[i*3+1] = (i+1)*2 + 1; indices[i*3+2] = i*2 + 1; } indices[NUMVERTS*3-2] = 1; rw::im3d::Transform(shape, NUMVERTS*2+1, nil, rw::im3d::ALLOPAQUE); rw::im3d::RenderIndexedPrimitive(rw::PRIMTYPETRILIST, indices, NUMVERTS*3); rw::im3d::End(); // top cap at = rw::scale(matrix->at, -(CONE_SIZE + 1.0f)); shape[NUMVERTS*2].setX(pos->x + at.x); shape[NUMVERTS*2].setY(pos->y + at.y); shape[NUMVERTS*2].setZ(pos->z + at.z); for(i = 0; i < NUMVERTS; i++){ indices[i*3+0] = NUMVERTS*2; indices[i*3+1] = i*2; indices[i*3+2] = (i+1)*2; } rw::im3d::Transform(shape, NUMVERTS*2+1, nil, rw::im3d::ALLOPAQUE); rw::im3d::RenderIndexedPrimitive(rw::PRIMTYPETRILIST, indices, NUMVERTS*3); rw::im3d::End(); // cone DrawCone(CONE_ANGLE, CONE_SIZE, -2.0f); } void DrawCurrentLight(void) { rw::SetRenderState(rw::TEXTURERASTER, nil); rw::SetRenderState(rw::CULLMODE, rw::CULLBACK); rw::SetRenderState(rw::ZTESTENABLE, 1); switch(LightTypeIndex){ case 1: DrawPointLight(); break; case 2: DrawDirectLight(); break; case 3: case 4: DrawCone(LightConeAngle, LightRadius*POINT_LIGHT_RADIUS_FACTOR, 1.0f); break; } } void LightRotate(float xAngle, float yAngle) { if(CurrentLight == nil || CurrentLight == AmbientLight || CurrentLight == PointLight) return; rw::Matrix *cameraMatrix = &Camera->getFrame()->matrix; rw::Frame *lightFrame = CurrentLight->getFrame(); rw::V3d pos = lightFrame->matrix.pos; pos = rw::scale(pos, -1.0f); lightFrame->translate(&pos, rw::COMBINEPOSTCONCAT); lightFrame->rotate(&cameraMatrix->up, xAngle, rw::COMBINEPOSTCONCAT); lightFrame->rotate(&cameraMatrix->right, yAngle, rw::COMBINEPOSTCONCAT); pos = rw::scale(pos, -1.0f); lightFrame->translate(&pos, rw::COMBINEPOSTCONCAT); } void ClampPosition(rw::V3d *pos, rw::V3d *delta, rw::BBox *bbox) { if(pos->x + delta->x < bbox->inf.x) delta->x = bbox->inf.x - pos->x; else if(pos->x + delta->x > bbox->sup.x) delta->x = bbox->sup.x - pos->x; if(pos->y + delta->y < bbox->inf.y) delta->y = bbox->inf.y - pos->y; else if(pos->y + delta->y > bbox->sup.y) delta->y = bbox->sup.y - pos->y; if(pos->z + delta->z < bbox->inf.z) delta->z = bbox->inf.z - pos->z; else if(pos->z + delta->z > bbox->sup.z) delta->z = bbox->sup.z - pos->z; } void LightTranslateXY(float xDelta, float yDelta) { if(CurrentLight == nil || CurrentLight == AmbientLight || CurrentLight == DirectLight) return; rw::Matrix *cameraMatrix = &Camera->getFrame()->matrix; rw::Frame *lightFrame = CurrentLight->getFrame(); rw::V3d right = rw::scale(cameraMatrix->right, xDelta); rw::V3d up = rw::scale(cameraMatrix->up, yDelta); rw::V3d delta = rw::add(right, up); ClampPosition(&lightFrame->matrix.pos, &delta, &RoomBBox); lightFrame->translate(&delta, rw::COMBINEPOSTCONCAT); } void LightTranslateZ(float zDelta) { if(CurrentLight == nil || CurrentLight == AmbientLight || CurrentLight == DirectLight) return; rw::Matrix *cameraMatrix = &Camera->getFrame()->matrix; rw::Frame *lightFrame = CurrentLight->getFrame(); rw::V3d delta = rw::scale(cameraMatrix->at, zDelta); ClampPosition(&lightFrame->matrix.pos, &delta, &RoomBBox); lightFrame->translate(&delta, rw::COMBINEPOSTCONCAT); } */