From f47bd33a6a3e32d09e323adf929b75e90457ddbf Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 19 Apr 2020 13:00:35 +0200 Subject: [PATCH] implemented generic lighting callback --- premake5.lua | 9 +- src/charset.cpp | 3 - src/d3d/d3d8render.cpp | 2 +- src/d3d/d3d9render.cpp | 2 +- src/d3d/d3drender.cpp | 102 +++++++--- src/d3d/rwd3d.h | 2 +- src/rwobjects.h | 15 +- src/world.cpp | 72 ++++++- tools/clumpview/font.cpp | 13 ++ tools/clumpview/main.cpp | 17 +- tools/clumpview/tl_tests.cpp | 2 +- tools/imguitest/main.cpp | 4 + tools/lights/checker.dff | Bin 0 -> 14348 bytes tools/lights/main.cpp | 365 +++++++++++++++++++++++++++++++++++ 14 files changed, 566 insertions(+), 42 deletions(-) create mode 100644 tools/lights/checker.dff create mode 100644 tools/lights/main.cpp diff --git a/premake5.lua b/premake5.lua index 0fa76f9..f44cdf9 100644 --- a/premake5.lua +++ b/premake5.lua @@ -204,7 +204,14 @@ project "imguitest" kind "WindowedApp" characterset ("MBCS") skeltool("imguitest") - files { "tools/imguitest/imgui/*.cpp" } + flags { "WinMain" } + removeplatforms { "*null" } + removeplatforms { "ps2" } + +project "lights" + kind "WindowedApp" + characterset ("MBCS") + skeltool("lights") flags { "WinMain" } removeplatforms { "*null" } removeplatforms { "ps2" } diff --git a/src/charset.cpp b/src/charset.cpp index 072444b..0001804 100644 --- a/src/charset.cpp +++ b/src/charset.cpp @@ -1,7 +1,4 @@ #include -//#include -//#include -//#include #include "rwbase.h" #include "rwerror.h" diff --git a/src/d3d/d3d8render.cpp b/src/d3d/d3d8render.cpp index 3fa0d39..aaaecc0 100644 --- a/src/d3d/d3d8render.cpp +++ b/src/d3d/d3d8render.cpp @@ -27,7 +27,7 @@ defaultRenderCB(Atomic *atomic, InstanceDataHeader *header) { RawMatrix world; - d3d::lightingCB(!!(atomic->geometry->flags & Geometry::NORMALS)); + d3d::lightingCB(atomic); Geometry *geo = atomic->geometry; d3d::setRenderState(D3DRS_LIGHTING, !!(geo->flags & rw::Geometry::LIGHT)); diff --git a/src/d3d/d3d9render.cpp b/src/d3d/d3d9render.cpp index f2a25c5..e2709b4 100644 --- a/src/d3d/d3d9render.cpp +++ b/src/d3d/d3d9render.cpp @@ -66,7 +66,7 @@ defaultRenderCB(Atomic *atomic, InstanceDataHeader *header) int lighting = !!(geo->flags & rw::Geometry::LIGHT); if(lighting) - d3d::lightingCB(!!(atomic->geometry->flags & Geometry::NORMALS)); + d3d::lightingCB(atomic); d3d::setRenderState(D3DRS_LIGHTING, lighting); diff --git a/src/d3d/d3drender.cpp b/src/d3d/d3drender.cpp index 072d0fa..33b6a5d 100644 --- a/src/d3d/d3drender.cpp +++ b/src/d3d/d3drender.cpp @@ -20,10 +20,19 @@ IDirect3DDevice9 *d3ddevice = nil; #define MAX_LIGHTS 8 void -lightingCB(bool32 normals) +lightingCB(Atomic *atomic) { - World *world; - RGBAf ambLight = { 0.0, 0.0, 0.0, 1.0 }; + WorldLights lightData; + Light *directionals[8]; + Light *locals[8]; + lightData.directionals = directionals; + lightData.numDirectionals = 8; + lightData.locals = locals; + lightData.numLocals = 8; + + ((World*)engine->currentWorld)->enumerateLights(atomic, &lightData); + + int i, n; RGBA amb; D3DLIGHT9 light; light.Type = D3DLIGHT_DIRECTIONAL; @@ -39,34 +48,83 @@ lightingCB(bool32 normals) light.Attenuation2 = 0.0f; light.Theta = 0.0f; light.Phi = 0.0f; - int n = 0; - world = (World*)engine->currentWorld; - // only unpositioned lights right now - FORLIST(lnk, world->directionalLights){ - Light *l = Light::fromWorld(lnk); - if((l->getFlags() & Light::LIGHTATOMICS) == 0) - continue; - if(normals && - l->getType() == Light::DIRECTIONAL && - l->getFlags() & Light::LIGHTATOMICS){ - if(n >= MAX_LIGHTS) - continue; + convColor(&amb, &lightData.ambient); + d3d::setRenderState(D3DRS_AMBIENT, D3DCOLOR_RGBA(amb.red, amb.green, amb.blue, amb.alpha)); + + n = 0; + for(i = 0; i < lightData.numDirectionals; i++){ + if(n >= MAX_LIGHTS) + return; + Light *l = lightData.directionals[i]; + light.Type = D3DLIGHT_DIRECTIONAL; + light.Diffuse = *(D3DCOLORVALUE*)&l->color; + light.Direction = *(D3DVECTOR*)&l->getFrame()->getLTM()->at; + d3ddevice->SetLight(n, &light); + d3ddevice->LightEnable(n, TRUE); + n++; + } + + for(i = 0; i < lightData.numLocals; i++){ + if(n >= MAX_LIGHTS) + return; + Light *l = lightData.locals[i]; + switch(l->getType()){ + case Light::POINT: + light.Type = D3DLIGHT_POINT; light.Diffuse = *(D3DCOLORVALUE*)&l->color; - light.Direction = *(D3DVECTOR*)&l->getFrame()->getLTM()->at; + light.Position = *(D3DVECTOR*)&l->getFrame()->getLTM()->pos; + light.Direction.x = 0.0f; + light.Direction.y = 0.0f; + light.Direction.z = 0.0f; + light.Range = l->radius; + light.Falloff = 1.0f; + light.Attenuation0 = 1.0f; + light.Attenuation1 = 0.0f/l->radius; + light.Attenuation2 = 5.0f/(l->radius*l->radius); d3ddevice->SetLight(n, &light); d3ddevice->LightEnable(n, TRUE); n++; - }else if(l->getType() == Light::AMBIENT){ - ambLight.red += l->color.red; - ambLight.green += l->color.green; - ambLight.blue += l->color.blue; + break; + + case Light::SPOT: + light.Type = D3DLIGHT_SPOT; + light.Diffuse = *(D3DCOLORVALUE*)&l->color; + light.Position = *(D3DVECTOR*)&l->getFrame()->getLTM()->pos; + light.Direction = *(D3DVECTOR*)&l->getFrame()->getLTM()->at; + light.Range = l->radius; + light.Falloff = 1.0f; + light.Attenuation0 = 1.0f; + light.Attenuation1 = 0.0f/l->radius; + light.Attenuation2 = 5.0f/(l->radius*l->radius); + light.Theta = l->getAngle()*2.0f; + light.Phi = light.Theta; + d3ddevice->SetLight(n, &light); + d3ddevice->LightEnable(n, TRUE); + n++; + break; + + case Light::SOFTSPOT: + light.Type = D3DLIGHT_SPOT; + light.Diffuse = *(D3DCOLORVALUE*)&l->color; + light.Position = *(D3DVECTOR*)&l->getFrame()->getLTM()->pos; + light.Direction = *(D3DVECTOR*)&l->getFrame()->getLTM()->at; + light.Range = l->radius; + light.Falloff = 1.0f; + light.Attenuation0 = 1.0f; + light.Attenuation1 = 0.0f/l->radius; + light.Attenuation2 = 5.0f/(l->radius*l->radius); + light.Theta = 0.0f; + light.Phi = l->getAngle()*2.0f; + d3ddevice->SetLight(n, &light); + d3ddevice->LightEnable(n, TRUE); + n++; + break; } } + for(; n < MAX_LIGHTS; n++) d3ddevice->LightEnable(n, FALSE); - convColor(&amb, &ambLight); - d3d::setRenderState(D3DRS_AMBIENT, D3DCOLOR_RGBA(amb.red, amb.green, amb.blue, amb.alpha)); } #endif diff --git a/src/d3d/rwd3d.h b/src/d3d/rwd3d.h index 1e8518b..4b510cd 100644 --- a/src/d3d/rwd3d.h +++ b/src/d3d/rwd3d.h @@ -37,7 +37,7 @@ extern IDirect3DDevice9 *d3ddevice; void setD3dMaterial(D3DMATERIAL9 *mat9); #endif -void lightingCB(bool32 normals); +void lightingCB(Atomic *atomic); #define COLOR_ARGB(a, r, g, b) ((rw::uint32)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))) diff --git a/src/rwobjects.h b/src/rwobjects.h index 68eb4cc..3f32ba8 100644 --- a/src/rwobjects.h +++ b/src/rwobjects.h @@ -731,14 +731,24 @@ struct Clump void render(void); }; +// used by enumerateLights for lighting callback +struct WorldLights +{ + RGBAf ambient; // all ambients added + int32 numDirectionals; + Light **directionals; // only directionals + int32 numLocals; + Light **locals; // points, (soft)spots +}; + // A bit of a stub right now struct World { PLUGINBASE enum { ID = 7 }; Object object; - LinkList lights; // these have positions (type >= 0x80) - LinkList directionalLights; // these do not (type < 0x80) + LinkList localLights; // these have positions (type >= 0x80) + LinkList globalLights; // these do not (type < 0x80) LinkList clumps; static int32 numAllocated; @@ -754,6 +764,7 @@ struct World void addClump(Clump *clump); void removeClump(Clump *clump); void render(void); + void enumerateLights(Atomic *atomic, WorldLights *lightData); }; struct TexDictionary diff --git a/src/world.cpp b/src/world.cpp index f724a5d..abe1a0c 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -28,8 +28,8 @@ World::create(void) } numAllocated++; world->object.init(World::ID, 0); - world->lights.init(); - world->directionalLights.init(); + world->localLights.init(); + world->globalLights.init(); world->clumps.init(); s_plglist.construct(world); return world; @@ -46,11 +46,12 @@ World::destroy(void) void World::addLight(Light *light) { + assert(light->world == nil); light->world = this; if(light->getType() < Light::POINT){ - this->directionalLights.append(&light->inWorld); + this->globalLights.append(&light->inWorld); }else{ - this->lights.append(&light->inWorld); + this->localLights.append(&light->inWorld); if(light->getFrame()) light->getFrame()->updateObjects(); } @@ -59,8 +60,9 @@ World::addLight(Light *light) void World::removeLight(Light *light) { - if(light->world == this) - light->inWorld.remove(); + assert(light->world == this); + light->inWorld.remove(); + light->world = nil; } void @@ -75,8 +77,8 @@ World::addCamera(Camera *cam) void World::removeCamera(Camera *cam) { - if(cam->world == this) - cam->world = nil; + assert(cam->world == this); + cam->world = nil; } void @@ -136,4 +138,58 @@ World::render(void) Clump::fromWorld(lnk)->render(); } +// Find lights that illuminate an atomic +void +World::enumerateLights(Atomic *atomic, WorldLights *lightData) +{ + int32 maxDirectionals, maxLocals; + + assert(atomic->world == this); + + maxDirectionals = lightData->numDirectionals; + maxLocals = lightData->numLocals; + + lightData->numDirectionals = 0; + lightData->numLocals = 0; + lightData->ambient.red = 0.0f; + lightData->ambient.green = 0.0f; + lightData->ambient.blue = 0.0f; + lightData->ambient.alpha = 1.0f; + + bool32 normals = atomic->geometry->flags & Geometry::NORMALS; + + FORLIST(lnk, this->globalLights){ + Light *l = Light::fromWorld(lnk); + if((l->getFlags() & Light::LIGHTATOMICS) == 0) + continue; + if(l->getType() == Light::AMBIENT){ + lightData->ambient.red += l->color.red; + lightData->ambient.green += l->color.green; + lightData->ambient.blue += l->color.blue; + }else if(normals && l->getType() == Light::DIRECTIONAL){ + if(lightData->numDirectionals < maxDirectionals) + lightData->directionals[lightData->numDirectionals++] = l; + } + } + + if(!normals) + return; + + // TODO: for this we would use an atomic's world sectors, but we don't have those yet + FORLIST(lnk, this->localLights){ + if(lightData->numLocals >= maxLocals) + return; + + Light *l = Light::fromWorld(lnk); + if((l->getFlags() & Light::LIGHTATOMICS) == 0) + continue; + + // check if spheres are intersecting + Sphere *atomsphere = atomic->getWorldBoundingSphere(); + V3d dist = sub(l->getFrame()->getLTM()->pos, atomsphere->center); + if(length(dist) < atomsphere->radius + l->radius) + lightData->locals[lightData->numLocals++] = l; + } +} + } diff --git a/tools/clumpview/font.cpp b/tools/clumpview/font.cpp index f95a01e..3ced5fb 100644 --- a/tools/clumpview/font.cpp +++ b/tools/clumpview/font.cpp @@ -111,6 +111,19 @@ 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"); + } +*/ } /* diff --git a/tools/clumpview/main.cpp b/tools/clumpview/main.cpp index 8d659cb..4d764b9 100644 --- a/tools/clumpview/main.cpp +++ b/tools/clumpview/main.cpp @@ -27,6 +27,8 @@ void genIm3DEnd(void); void initFont(void); void printScreen(const char *s, float x, float y); +rw::Charset *testfont; + //#include void @@ -177,9 +179,18 @@ InitRW(void) if(!sk::InitRW()) return false; + rw::d3d::isP8supported = false; + initFont(); - rw::d3d::isP8supported = false; + 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); @@ -327,7 +338,8 @@ im3dtest(void) verts[i].setV(vs[i].v); } - rw::SetRenderStatePtr(rw::TEXTURERASTER, tex->raster); +// 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); @@ -392,6 +404,7 @@ extern void endSoftras(void); im3dtest(); // printScreen("Hello, World!", 10, 10); + testfont->print("foo ABC", 200, 200, true); camera->m_rwcam->endUpdate(); diff --git a/tools/clumpview/tl_tests.cpp b/tools/clumpview/tl_tests.cpp index dfee700..19e7f3a 100644 --- a/tools/clumpview/tl_tests.cpp +++ b/tools/clumpview/tl_tests.cpp @@ -37,7 +37,7 @@ enumLights(Matrix *lightmat) ambLight.alpha = 0.0; numDirectionals = 0; // only unpositioned lights right now - FORLIST(lnk, world->directionalLights){ + FORLIST(lnk, world->globalLights){ Light *l = Light::fromWorld(lnk); if(l->getType() == Light::DIRECTIONAL){ if(numDirectionals >= MAX_LIGHTS) diff --git a/tools/imguitest/main.cpp b/tools/imguitest/main.cpp index 675f095..fb80e08 100644 --- a/tools/imguitest/main.cpp +++ b/tools/imguitest/main.cpp @@ -155,6 +155,10 @@ AppEventHandler(sk::Event e, void *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 diff --git a/tools/lights/checker.dff b/tools/lights/checker.dff new file mode 100644 index 0000000000000000000000000000000000000000..f955e8cc2c32f1df76643491d0ad62ac419e8e3f GIT binary patch literal 14348 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 +#include +#include + +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(); +} + + +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; +}