diff --git a/premake5.lua b/premake5.lua index 484e407..141432e 100755 --- a/premake5.lua +++ b/premake5.lua @@ -209,6 +209,14 @@ project "lights" removeplatforms { "*null" } removeplatforms { "ps2" } +project "subrast" + kind "WindowedApp" + characterset ("MBCS") + skeltool("subrast") + flags { "WinMain" } + removeplatforms { "*null" } + removeplatforms { "ps2" } + project "ska2anm" kind "ConsoleApp" characterset ("MBCS") diff --git a/skeleton/skeleton.cpp b/skeleton/skeleton.cpp index 740a3ab..3defebe 100644 --- a/skeleton/skeleton.cpp +++ b/skeleton/skeleton.cpp @@ -47,6 +47,8 @@ InitRW(void) if(!rw::Engine::start()) return false; + rw::Charset::open(); + rw::Image::setSearchPath("./"); return true; } @@ -54,6 +56,8 @@ InitRW(void) void TerminateRW(void) { + rw::Charset::close(); + // TODO: delete all tex dicts rw::Engine::stop(); rw::Engine::close(); diff --git a/src/charset.cpp b/src/charset.cpp index 0d94be8..5188b80 100644 --- a/src/charset.cpp +++ b/src/charset.cpp @@ -128,8 +128,16 @@ Charset::flushBuffer(void) rw::SetRenderState(rw::TEXTUREADDRESS, rw::Texture::WRAP); rw::SetRenderState(rw::TEXTUREFILTER, rw::Texture::NEAREST); + uint32 cull = rw::GetRenderState(rw::CULLMODE); + uint32 ztest = rw::GetRenderState(rw::ZTESTENABLE); + rw::SetRenderState(rw::CULLMODE, rw::CULLNONE); + rw::SetRenderState(rw::ZTESTENABLE, 0); + im2d::RenderIndexedPrimitive(rw::PRIMTYPETRILIST, vertices, numChars*4, indices, numChars*6); + + rw::SetRenderState(rw::CULLMODE, cull); + rw::SetRenderState(rw::ZTESTENABLE, ztest); } numChars = 0; diff --git a/src/d3d/d3d.cpp b/src/d3d/d3d.cpp index 55608a5..f1f5f49 100644 --- a/src/d3d/d3d.cpp +++ b/src/d3d/d3d.cpp @@ -18,7 +18,7 @@ namespace rw { namespace d3d { -bool32 isP8supported = 1; +bool32 isP8supported = 1; // set to 0 when actual d3d device is used // stolen from d3d8to9 static uint32 diff --git a/src/d3d/d3ddevice.cpp b/src/d3d/d3ddevice.cpp index 922530c..1f39f18 100644 --- a/src/d3d/d3ddevice.cpp +++ b/src/d3d/d3ddevice.cpp @@ -944,6 +944,9 @@ setRenderSurfaces(Camera *cam) Raster *fbuf = cam->frameBuffer; assert(fbuf); { + if(fbuf->parent) + fbuf = fbuf->parent; + D3dRaster *natras = GETD3DRASTEREXT(fbuf); assert(fbuf->type == Raster::CAMERA || fbuf->type == Raster::CAMERATEXTURE); if(natras->texture == nil) @@ -959,6 +962,9 @@ setRenderSurfaces(Camera *cam) Raster *zbuf = cam->zBuffer; if(zbuf){ + if(zbuf->parent) + zbuf = zbuf->parent; + D3dRaster *natras = GETD3DRASTEREXT(zbuf); assert(zbuf->type == Raster::ZBUFFER); setDepthSurface(natras->texture); @@ -967,6 +973,19 @@ setRenderSurfaces(Camera *cam) } +static void +setViewport(Raster *fb) +{ + D3DVIEWPORT9 vp; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + vp.X = fb->offsetX; + vp.Y = fb->offsetY; + vp.Width = fb->width; + vp.Height = fb->height; + d3ddevice->SetViewport(&vp); +} + static void beginUpdate(Camera *cam) { @@ -1046,23 +1065,14 @@ beginUpdate(Camera *cam) setRenderSurfaces(cam); - D3DVIEWPORT9 vp; - vp.MinZ = 0.0f; - vp.MaxZ = 1.0f; - vp.X = cam->frameBuffer->offsetX; - vp.Y = cam->frameBuffer->offsetY; - vp.Width = cam->frameBuffer->width; - vp.Height = cam->frameBuffer->height; - d3ddevice->SetViewport(&vp); + setViewport(cam->frameBuffer); - // TODO: figure out when to call this d3ddevice->BeginScene(); } static void endUpdate(Camera *cam) { - // TODO: figure out when to call this d3ddevice->EndScene(); } @@ -1314,7 +1324,6 @@ clearCamera(Camera *cam, RGBA *col, uint32 mode) RECT r; GetClientRect(d3d9Globals.window, &r); BOOL icon = IsIconic(d3d9Globals.window); - Raster *ras = cam->frameBuffer; if(!icon && (r.right != d3d9Globals.present.BackBufferWidth || r.bottom != d3d9Globals.present.BackBufferHeight)){ @@ -1328,7 +1337,8 @@ clearCamera(Camera *cam, RGBA *col, uint32 mode) setRenderSurfaces(cam); - d3ddevice->Clear(0, 0, mode, c, 1.0f, 0); + setViewport(cam->frameBuffer); // need to set this for the clear to work correctly + d3ddevice->Clear(0, nil, mode, c, 1.0f, 0); } static void @@ -1604,6 +1614,8 @@ startD3D(void) // d3d9Globals.present.PresentationInterval = D3DPRESENT_INTERVAL_ONE; d3d9Globals.present.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + rw::d3d::isP8supported = 0; + assert(d3d::d3ddevice == nil); BOOL icon = IsIconic(d3d9Globals.window); diff --git a/src/gl/gl3device.cpp b/src/gl/gl3device.cpp index 90ac299..e9ea6f3 100644 --- a/src/gl/gl3device.cpp +++ b/src/gl/gl3device.cpp @@ -1225,6 +1225,50 @@ setFrameBuffer(Camera *cam) } } +static Rect +getFramebufferRect(Raster *frameBuffer) +{ + Rect r; + Raster *fb = frameBuffer->parent; + if(fb->type == Raster::CAMERA){ +#ifdef LIBRW_SDL2 + SDL_GetWindowSize(glGlobals.window, &r.w, &r.h); +#else + glfwGetFramebufferSize(glGlobals.window, &r.w, &r.h); +#endif + }else{ + r.w = fb->width; + r.h = fb->height; + } + r.x = 0; + r.y = 0; + + // Got a subraster + if(frameBuffer != fb){ + r.x = frameBuffer->offsetX; + // GL y offset is from bottom + r.y = r.h - frameBuffer->height - frameBuffer->offsetY; + r.w = frameBuffer->width; + r.h = frameBuffer->height; + } + + return r; +} + +static void +setViewport(Raster *frameBuffer) +{ + Rect r = getFramebufferRect(frameBuffer); + if(r.w != glGlobals.presentWidth || r.h != glGlobals.presentHeight || + r.x != glGlobals.presentOffX || r.y != glGlobals.presentOffY){ + glViewport(r.x, r.y, r.w, r.h); + glGlobals.presentWidth = r.w; + glGlobals.presentHeight = r.h; + glGlobals.presentOffX = r.x; + glGlobals.presentOffY = r.y; + } +} + static void beginUpdate(Camera *cam) { @@ -1279,10 +1323,10 @@ beginUpdate(Camera *cam) proj[14] = -2.0f*cam->nearPlane*cam->farPlane*invz; proj[15] = 0.0f; }else{ - proj[10] = -(cam->farPlane+cam->nearPlane)*invz; + proj[10] = 2.0f*invz; proj[11] = 0.0f; - proj[14] = 2.0f*invz; + proj[14] = -(cam->farPlane+cam->nearPlane)*invz; proj[15] = 1.0f; } memcpy(&cam->devProj, &proj, sizeof(RawMatrix)); @@ -1301,39 +1345,7 @@ beginUpdate(Camera *cam) setFrameBuffer(cam); - int w, h; - int x, y; - Raster *fb = cam->frameBuffer->parent; - if(fb->type == Raster::CAMERA){ -#ifdef LIBRW_SDL2 - SDL_GetWindowSize(glGlobals.window, &w, &h); -#else - glfwGetFramebufferSize(glGlobals.window, &w, &h); -#endif - }else{ - w = fb->width; - h = fb->height; - } - x = 0; - y = 0; - - // Got a subraster - if(cam->frameBuffer != fb){ - x = cam->frameBuffer->offsetX; - // GL y offset is from bottom - y = h - cam->frameBuffer->height - cam->frameBuffer->offsetY; - w = cam->frameBuffer->width; - h = cam->frameBuffer->height; - } - - if(w != glGlobals.presentWidth || h != glGlobals.presentHeight || - x != glGlobals.presentOffX || y != glGlobals.presentOffY){ - glViewport(x, y, w, h); - glGlobals.presentWidth = w; - glGlobals.presentHeight = h; - glGlobals.presentOffX = x; - glGlobals.presentOffY = y; - } + setViewport(cam->frameBuffer); } static void @@ -1349,6 +1361,15 @@ clearCamera(Camera *cam, RGBA *col, uint32 mode) setFrameBuffer(cam); + // make sure we're only clearing the part of the framebuffer + // that is subrastered + bool setScissor = cam->frameBuffer != cam->frameBuffer->parent; + if(setScissor){ + Rect r = getFramebufferRect(cam->frameBuffer); + glScissor(r.x, r.y, r.w, r.h); + glEnable(GL_SCISSOR_TEST); + } + convColor(&colf, col); glClearColor(colf.red, colf.green, colf.blue, colf.alpha); mask = 0; @@ -1361,12 +1382,17 @@ clearCamera(Camera *cam, RGBA *col, uint32 mode) glDepthMask(GL_TRUE); glClear(mask); glDepthMask(rwStateCache.zwrite); + + if(setScissor) + glDisable(GL_SCISSOR_TEST); } static void showRaster(Raster *raster, uint32 flags) { - // TODO: do this properly! +// glViewport(raster->offsetX, raster->offsetY, +// raster->width, raster->height); + #ifdef LIBRW_SDL2 if(flags & Raster::FLIPWAITVSYNCH) SDL_GL_SetSwapInterval(1); @@ -1746,8 +1772,8 @@ initOpenGL(void) // printf("%d %s\n", i, ext); } */ - gl3Caps.dxtSupported = GLAD_GL_EXT_texture_compression_s3tc; - gl3Caps.astcSupported = GLAD_GL_KHR_texture_compression_astc_ldr; + gl3Caps.dxtSupported = !!GLAD_GL_EXT_texture_compression_s3tc; + gl3Caps.astcSupported = !!GLAD_GL_KHR_texture_compression_astc_ldr; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl3Caps.maxAnisotropy); diff --git a/src/raster.cpp b/src/raster.cpp index fb654ef..c7ebffe 100644 --- a/src/raster.cpp +++ b/src/raster.cpp @@ -87,8 +87,8 @@ Raster::subRaster(Raster *parent, Rect *r) return; this->width = r->w; this->height = r->h; - this->offsetX += r->x; - this->offsetY += r->y; + this->offsetX = parent->offsetX + r->x; + this->offsetY = parent->offsetY + r->y; this->parent = parent->parent; } diff --git a/tools/subrast/files/clump.dff b/tools/subrast/files/clump.dff new file mode 100644 index 0000000..b65e41d Binary files /dev/null and b/tools/subrast/files/clump.dff differ diff --git a/tools/subrast/files/textures/whiteash.png b/tools/subrast/files/textures/whiteash.png new file mode 100644 index 0000000..aa60569 Binary files /dev/null and b/tools/subrast/files/textures/whiteash.png differ diff --git a/tools/subrast/main.cpp b/tools/subrast/main.cpp new file mode 100644 index 0000000..a86f373 --- /dev/null +++ b/tools/subrast/main.cpp @@ -0,0 +1,352 @@ +#include +#include +#include + +#include "subrast.h" + +rw::V3d zero = { 0.0f, 0.0f, 0.0f }; +rw::EngineOpenParams engineOpenParams; +float FOV = 70.0f; + +rw::RGBA ForegroundColor = { 200, 200, 200, 255 }; +rw::RGBA BackgroundColor = { 64, 64, 64, 0 }; +rw::RGBA BorderColor = { 128, 128, 128, 0 }; + +rw::Clump *Clump = nil; +rw::Light *MainLight = nil; +rw::Light *AmbientLight = nil; + +rw::World *World; +rw::Charset *Charset; + +const char *SubCameraCaption[4] = { + "Perspective view", + "Parallel view: Z-axis", + "Parallel view: X-axis", + "Parallel view: Y-axis" +}; + +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::World* +CreateWorld(void) +{ + rw::BBox bb; + + bb.inf.x = bb.inf.y = bb.inf.z = -100.0f; + bb.sup.x = bb.sup.y = bb.sup.z = 100.0f; + + return rw::World::create(&bb); +} + +rw::Light* +CreateAmbientLight(rw::World *world) +{ + rw::Light *light = rw::Light::create(rw::Light::AMBIENT); + assert(light); + World->addLight(light); + return light; +} + +rw::Light* +CreateMainLight(rw::World *world) +{ + rw::Light *light = rw::Light::create(rw::Light::DIRECTIONAL); + assert(light); + rw::Frame *frame = rw::Frame::create(); + assert(frame); + frame->rotate(&Xaxis, 30.0f, rw::COMBINEREPLACE); + frame->rotate(&Yaxis, 30.0f, rw::COMBINEPOSTCONCAT); + light->setFrame(frame); + World->addLight(light); + return light; +} + +rw::Clump* +CreateClump(rw::World *world) +{ + rw::Clump *clump; + rw::StreamFile in; + + rw::Image::setSearchPath("files/textures/"); + const char *filename = "files/clump.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::Frame *frame = clump->getFrame(); + frame->rotate(&Xaxis, -120.0f, rw::COMBINEREPLACE); + frame->rotate(&Yaxis, 45.0f, rw::COMBINEPOSTCONCAT); + World->addClump(clump); + return clump; +} + +void +RotateClump(float xAngle, float yAngle) +{ + rw::Matrix *cameraMatrix = &Camera->getFrame()->matrix; + rw::Frame *frame = Clump->getFrame(); + rw::V3d pos = frame->matrix.pos; + + pos = rw::scale(pos, -1.0f); + frame->translate(&pos, rw::COMBINEPOSTCONCAT); + + frame->rotate(&cameraMatrix->up, xAngle, rw::COMBINEPOSTCONCAT); + frame->rotate(&cameraMatrix->right, yAngle, rw::COMBINEPOSTCONCAT); + + pos = rw::scale(pos, -1.0f); + frame->translate(&pos, rw::COMBINEPOSTCONCAT); +} + +void +Initialize(void) +{ + sk::globals.windowtitle = "Sub-raster example"; + sk::globals.width = 1280; + sk::globals.height = 800; + sk::globals.quit = 0; +} + +bool +Initialize3D(void) +{ + if(!sk::InitRW()) + return false; + + Charset = rw::Charset::create(&ForegroundColor, &BackgroundColor); + + World = CreateWorld(); + + AmbientLight = CreateAmbientLight(World); + MainLight = CreateMainLight(World); + Clump = CreateClump(World); + + CreateCameras(World); +UpdateSubRasters(Camera, sk::globals.width, sk::globals.height); + + rw::SetRenderState(rw::CULLMODE, rw::CULLBACK); + rw::SetRenderState(rw::ZTESTENABLE, 1); + rw::SetRenderState(rw::ZWRITEENABLE, 1); + + ImGui_ImplRW_Init(); + ImGui::StyleColorsClassic(); + + return true; +} + +void +Terminate3D(void) +{ + DestroyCameras(World); + + if(AmbientLight){ + World->removeLight(AmbientLight); + AmbientLight->destroy(); + AmbientLight = nil; + } + + if(MainLight){ + World->removeLight(MainLight); + rw::Frame *frame = MainLight->getFrame(); + MainLight->setFrame(nil); + frame->destroy(); + MainLight->destroy(); + MainLight = nil; + } + + if(Clump){ + World->removeClump(Clump); + Clump->destroy(); + Clump = nil; + } + + if(World){ + World->destroy(); + World = nil; + } + + if(Charset){ + Charset->destroy(); + Charset = nil; + } + + sk::TerminateRW(); +} + +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 +DisplayOnScreenInfo(void) +{ + for(int i = 0; i < 4; i++){ + rw::Raster *scr = SubCameras[i]->frameBuffer; + + rw::int32 scrw = scr->width; + rw::int32 scrh = scr->height; + + rw::int32 captionWidth = strlen(SubCameraCaption[i])*Charset->desc.width; + + if(captionWidth < scrw && scrh > Charset->desc.height*2){ + rw::int32 x = scr->offsetX + (scrw - captionWidth)/2; + rw::int32 y = scr->offsetY + Charset->desc.height; + Charset->print(SubCameraCaption[i], x, y, 0); + } + } +} + +rw::RGBA BackgroundColors[] = { + { 64, 64, 64, 0 }, + { 128, 0, 0, 0 }, + { 0, 128, 0, 0 }, + { 0, 0, 128, 0 }, +}; +void +Render(float timeDelta) +{ + Camera->clear(&BorderColor, rw::Camera::CLEARIMAGE|rw::Camera::CLEARZ); + + for(int i = 0; i < 4; i++){ + SubCameras[i]->clear(&BackgroundColor, rw::Camera::CLEARIMAGE|rw::Camera::CLEARZ); +// SubCameras[i]->clear(&BackgroundColors[i], rw::Camera::CLEARIMAGE|rw::Camera::CLEARZ); + SubCameras[i]->beginUpdate(); + World->render(); + SubCameras[i]->endUpdate(); + } + + Camera->beginUpdate(); + DisplayOnScreenInfo(); + Camera->endUpdate(); + + Camera->showRaster(0); +} + +void +Idle(float timeDelta) +{ + Render(timeDelta); +} + +int MouseX, MouseY; +int MouseDeltaX, MouseDeltaY; +int MouseButtons; + +bool Rotating; + +void +KeyUp(int key) +{ +} + +void +KeyDown(int key) +{ + switch(key){ + case sk::KEY_ESC: + sk::globals.quit = 1; + break; + } +} + +void +MouseBtn(sk::MouseState *mouse) +{ + MouseButtons = mouse->buttons; + Rotating = !!(MouseButtons&1); +} + +void +MouseMove(sk::MouseState *mouse) +{ + MouseDeltaX = mouse->posx - MouseX; + MouseDeltaY = mouse->posy - MouseY; + MouseX = mouse->posx; + MouseY = mouse->posy; + if(Rotating) + RotateClump(-MouseDeltaX, MouseDeltaY); +} + +sk::EventStatus +AppEventHandler(sk::Event e, void *param) +{ + using namespace sk; + Rect *r; + MouseState *ms; + + ImGuiEventHandler(e, param); + ImGuiIO &io = ImGui::GetIO(); + + switch(e){ + case INITIALIZE: + Initialize(); + return EVENTPROCESSED; + case RWINITIALIZE: + return Initialize3D() ? EVENTPROCESSED : EVENTERROR; + case RWTERMINATE: + Terminate3D(); + return EVENTPROCESSED; + case PLUGINATTACH: + return attachPlugins() ? EVENTPROCESSED : EVENTERROR; + case KEYDOWN: + KeyDown(*(int*)param); + return EVENTPROCESSED; + case KEYUP: + KeyUp(*(int*)param); + return EVENTPROCESSED; + case MOUSEBTN: + if(!io.WantCaptureMouse){ + ms = (MouseState*)param; + MouseBtn(ms); + }else + MouseButtons = 0; + return EVENTPROCESSED; + case MOUSEMOVE: + MouseMove((MouseState*)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(::Camera){ + sk::CameraSize(::Camera, r); + ::Camera->setFOV(FOV, (float)sk::globals.width/sk::globals.height); + + UpdateSubRasters(::Camera, r->w, r->h); + } + break; + case IDLE: + Idle(*(float*)param); + return EVENTPROCESSED; + } + return sk::EVENTNOTPROCESSED; +} diff --git a/tools/subrast/subrast.cpp b/tools/subrast/subrast.cpp new file mode 100644 index 0000000..0ee4027 --- /dev/null +++ b/tools/subrast/subrast.cpp @@ -0,0 +1,592 @@ +#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); +} +*/ \ No newline at end of file diff --git a/tools/subrast/subrast.h b/tools/subrast/subrast.h new file mode 100644 index 0000000..b7c8537 --- /dev/null +++ b/tools/subrast/subrast.h @@ -0,0 +1,10 @@ +extern rw::Camera *Camera; +extern rw::Camera *SubCameras[4]; + +void CreateCameras(rw::World *world); +void DestroyCameras(rw::World *world); +void UpdateSubRasters(rw::Camera *mainCamera, rw::int32 mainWidth, rw::int32 mainHeight); + +extern rw::V3d Xaxis; +extern rw::V3d Yaxis; +extern rw::V3d Zaxis;