From 0921a2b003e87010eb2ce533771b05817f4e53bd Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 3 Mar 2021 02:00:52 +0100 Subject: [PATCH] finished lights example --- TODO | 10 + skeleton/imgui/imgui_impl_rw.cpp | 21 ++ src/render.cpp | 18 ++ src/rwobjects.h | 2 +- src/rwrender.h | 2 + src/world.cpp | 2 +- tools/lights/lights.cpp | 440 +++++++++++++++++++++++++++++++ tools/lights/lights.h | 36 +++ tools/lights/main.cpp | 343 ++++++++++++------------ tools/lights/main.h | 7 + 10 files changed, 708 insertions(+), 173 deletions(-) create mode 100644 tools/lights/lights.cpp create mode 100644 tools/lights/lights.h create mode 100644 tools/lights/main.h diff --git a/TODO b/TODO index c4d8cdb..b66a1fb 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,18 @@ TODO: - tristrips - examples + skeleton + interface + camera + camtex + subrast + matfx1 (more new shaders) + hanim1 + fog + imlight? + patch? - morphing - Pipelines (PDS, Xbox, PC) +- bsp driver - metrics diff --git a/skeleton/imgui/imgui_impl_rw.cpp b/skeleton/imgui/imgui_impl_rw.cpp index 6ea726f..a2ada39 100644 --- a/skeleton/imgui/imgui_impl_rw.cpp +++ b/skeleton/imgui/imgui_impl_rw.cpp @@ -55,10 +55,21 @@ ImGui_ImplRW_RenderDrawLists(ImDrawData* draw_data) vtx_dst += cmd_list->VtxBuffer.Size; } + int vertexAlpha = rw::GetRenderState(rw::VERTEXALPHA); + int srcBlend = rw::GetRenderState(rw::SRCBLEND); + int dstBlend = rw::GetRenderState(rw::DESTBLEND); + int ztest = rw::GetRenderState(rw::ZTESTENABLE); + void *tex = rw::GetRenderStatePtr(rw::TEXTURERASTER); + int addrU = rw::GetRenderState(rw::TEXTUREADDRESSU); + int addrV = rw::GetRenderState(rw::TEXTUREADDRESSV); + int filter = rw::GetRenderState(rw::TEXTUREFILTER); + int cullmode = rw::GetRenderState(rw::CULLMODE); + rw::SetRenderState(rw::VERTEXALPHA, 1); rw::SetRenderState(rw::SRCBLEND, rw::BLENDSRCALPHA); rw::SetRenderState(rw::DESTBLEND, rw::BLENDINVSRCALPHA); rw::SetRenderState(rw::ZTESTENABLE, 0); + rw::SetRenderState(rw::CULLMODE, rw::CULLNONE); int vtx_offset = 0; for(int n = 0; n < draw_data->CmdListsCount; n++){ @@ -85,6 +96,16 @@ ImGui_ImplRW_RenderDrawLists(ImDrawData* draw_data) } vtx_offset += cmd_list->VtxBuffer.Size; } + + rw::SetRenderState(rw::VERTEXALPHA,vertexAlpha); + rw::SetRenderState(rw::SRCBLEND, srcBlend); + rw::SetRenderState(rw::DESTBLEND, dstBlend); + rw::SetRenderState(rw::ZTESTENABLE, ztest); + rw::SetRenderStatePtr(rw::TEXTURERASTER, tex); + rw::SetRenderState(rw::TEXTUREADDRESSU, addrU); + rw::SetRenderState(rw::TEXTUREADDRESSV, addrV); + rw::SetRenderState(rw::TEXTUREFILTER, filter); + rw::SetRenderState(rw::CULLMODE, cullmode); } bool diff --git a/src/render.cpp b/src/render.cpp index 814f682..6822c24 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -3,6 +3,7 @@ #include "rwbase.h" #include "rwplg.h" #include "rwengine.h" +#include "rwrender.h" namespace rw { @@ -57,6 +58,23 @@ Transform(void *vertices, int32 numVertices, Matrix *world, uint32 flags) engine->device.im3DTransform(vertices, numVertices, world, flags); } void +RenderLine(int32 vert1, int32 vert2) +{ + int16 indices[2]; + indices[0] = vert1; + indices[1] = vert2; + RenderIndexedPrimitive(rw::PRIMTYPELINELIST, indices, 2); +} +void +RenderTriangle(int32 vert1, int32 vert2, int32 vert3) +{ + int16 indices[3]; + indices[0] = vert1; + indices[1] = vert2; + indices[2] = vert3; + RenderIndexedPrimitive(rw::PRIMTYPETRILIST, indices, 3); +} +void RenderPrimitive(PrimitiveType primType) { engine->device.im3DRenderPrimitive(primType); diff --git a/src/rwobjects.h b/src/rwobjects.h index 2a85586..3ecf14f 100644 --- a/src/rwobjects.h +++ b/src/rwobjects.h @@ -860,7 +860,7 @@ struct World static int32 numAllocated; - static World *create(void); + static World *create(BBox *bbox = nil); // TODO: should probably make this non-optional void destroy(void); void addLight(Light *light); void removeLight(Light *light); diff --git a/src/rwrender.h b/src/rwrender.h index 5882356..200837a 100644 --- a/src/rwrender.h +++ b/src/rwrender.h @@ -127,6 +127,8 @@ enum TransformFlags }; void Transform(void *vertices, int32 numVertices, Matrix *world, uint32 flags); +void RenderLine(int32 vert1, int32 vert2); +void RenderTriangle(int32 vert1, int32 vert2, int32 vert3); void RenderPrimitive(PrimitiveType primType); void RenderIndexedPrimitive(PrimitiveType primType, void *indices, int32 numIndices); void End(void); diff --git a/src/world.cpp b/src/world.cpp index 447eebc..6432b37 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -19,7 +19,7 @@ int32 World::numAllocated = 0; PluginList World::s_plglist(sizeof(World)); World* -World::create(void) +World::create(BBox *bbox) { World *world = (World*)rwMalloc(s_plglist.size, MEMDUR_EVENT | ID_WORLD); if(world == nil){ diff --git a/tools/lights/lights.cpp b/tools/lights/lights.cpp new file mode 100644 index 0000000..21786ed --- /dev/null +++ b/tools/lights/lights.cpp @@ -0,0 +1,440 @@ +#include +#include + +#include "main.h" + +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 +LightsDestroy(void) +{ + // TODO +} + +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); +} diff --git a/tools/lights/lights.h b/tools/lights/lights.h new file mode 100644 index 0000000..63a2990 --- /dev/null +++ b/tools/lights/lights.h @@ -0,0 +1,36 @@ + + +extern rw::Light *BaseAmbientLight; +extern bool BaseAmbientLightOn; + +extern rw::Light *CurrentLight; +extern rw::Light *AmbientLight; +extern rw::Light *PointLight; +extern rw::Light *DirectLight; +extern rw::Light *SpotLight; +extern rw::Light *SpotSoftLight; + +extern float LightRadius; +extern float LightConeAngle; +extern rw::RGBAf LightColor; + +extern bool LightOn; +extern bool LightDrawOn; +extern rw::V3d LightPos; +extern rw::int32 LightTypeIndex; + +extern rw::BBox RoomBBox; + +rw::Light *CreateBaseAmbientLight(void); +rw::Light *CreateAmbientLight(void); +rw::Light *CreateDirectLight(void); +rw::Light *CreatePointLight(void); +rw::Light *CreateSpotLight(void); +rw::Light *CreateSpotSoftLight(void); + +void LightsUpdate(void); +void DrawCurrentLight(void); + +void LightRotate(float xAngle, float yAngle); +void LightTranslateXY(float xDelta, float yDelta); +void LightTranslateZ(float zDelta); diff --git a/tools/lights/main.cpp b/tools/lights/main.cpp index 5d2bab1..6c8938d 100644 --- a/tools/lights/main.cpp +++ b/tools/lights/main.cpp @@ -2,134 +2,45 @@ #include #include +#include "main.h" +#include "lights.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::RGBA ForegroundColor = { 200, 200, 200, 255 }; +rw::RGBA BackgroundColor = { 64, 64, 64, 0 }; + +rw::World *World; +rw::Camera *Camera; + 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) +rw::World* +CreateWorld(void) { - sk::globals.windowtitle = "Light test"; - sk::globals.width = 1280; - sk::globals.height = 800; - sk::globals.quit = 0; + 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); } -bool -attachPlugins(void) +rw::Camera* +CreateCamera(rw::World *world) { - 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; + rw::Camera *camera; + camera = sk::CameraCreate(sk::globals.width, sk::globals.height, 1); + assert(camera); + camera->setNearPlane(0.1f); + camera->setFarPlane(300.0f); + camera->setFOV(FOV, (float)sk::globals.width/sk::globals.height); + world->addCamera(camera); + return camera; } bool @@ -208,17 +119,35 @@ CreateTestScene(rw::World *world) pos.z = zOffset + 25.0f; clumpFrame->translate(&pos, rw::COMBINEPOSTCONCAT); + // BBox + pos.x = 25.0f; + pos.y = 25.0f; + pos.z = zOffset - 25.0f; + RoomBBox.initialize(&pos); + pos.x = -25.0f; + pos.y = -25.0f; + pos.z = zOffset + 25.0f; + RoomBBox.addPoint(&pos); + return 1; } -bool -InitRW(void) +void +Initialize(void) +{ + sk::globals.windowtitle = "Lights example"; + sk::globals.width = 1280; + sk::globals.height = 800; + sk::globals.quit = 0; +} + +bool +Initialize3D(void) { -// rw::platform = rw::PLATFORM_D3D8; if(!sk::InitRW()) return false; - Scene.world = rw::World::create(); + World = CreateWorld(); BaseAmbientLight = CreateBaseAmbientLight(); AmbientLight = CreateAmbientLight(); @@ -227,13 +156,9 @@ InitRW(void) 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); + Camera = CreateCamera(World); - CreateTestScene(Scene.world); + CreateTestScene(World); ImGui_ImplRW_Init(); ImGui::StyleColorsClassic(); @@ -241,101 +166,167 @@ InitRW(void) return true; } -void -SwitchToLight(rw::Light *light) +bool +attachPlugins(void) { - if(CurrentLight) - Scene.world->removeLight(CurrentLight); - CurrentLight = light; - Scene.world->addLight(CurrentLight); + 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 Gui(void) { -// ImGui::ShowDemoWindow(&show_demo_window); +// ImGui::ShowDemoWindow(nil); 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::Checkbox("Light", &LightOn); + ImGui::Checkbox("Draw Light", &LightDrawOn); + if(ImGui::Checkbox("Base Ambient", &BaseAmbientLightOn)){ + if(BaseAmbientLightOn){ + if(BaseAmbientLight->world == nil) + World->addLight(BaseAmbientLight); + }else{ + if(BaseAmbientLight->world) + World->removeLight(BaseAmbientLight); + } } + + ImGui::RadioButton("Ambient Light", &LightTypeIndex, 0); + ImGui::RadioButton("Point Light", &LightTypeIndex, 1); + ImGui::RadioButton("Directional Light", &LightTypeIndex, 2); + ImGui::RadioButton("Spot Light", &LightTypeIndex, 3); + ImGui::RadioButton("Soft Spot Light", &LightTypeIndex, 4); + + ImGui::ColorEdit3("Color", (float*)&LightColor); + float radAngle = LightConeAngle/180.0f*M_PI; + ImGui::SliderAngle("Cone angle", &radAngle, 0.0f, 180.0f); + LightConeAngle = radAngle/M_PI*180.0f; + ImGui::SliderFloat("Radius", &LightRadius, 0.1f, 500.0f); + ImGui::End(); } void -Draw(float timeDelta) +Render(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(); + Camera->clear(&BackgroundColor, rw::Camera::CLEARIMAGE|rw::Camera::CLEARZ); + Camera->beginUpdate(); ImGui_ImplRW_NewFrame(timeDelta); - Scene.world->render(); + World->render(); + + if(LightDrawOn && CurrentLight) + DrawCurrentLight(); Gui(); ImGui::EndFrame(); ImGui::Render(); - Scene.camera->endUpdate(); - Scene.camera->showRaster(0); + Camera->endUpdate(); + Camera->showRaster(0); } +void +Idle(float timeDelta) +{ + LightsUpdate(); + + Render(timeDelta); +} + +int MouseX, MouseY; +int MouseDeltaX, MouseDeltaY; +int MouseButtons; + +int CtrlDown; + +bool RotateLight; +bool TranslateLightXY; +bool TranslateLightZ; void KeyUp(int key) { + switch(key){ + case sk::KEY_LCTRL: + case sk::KEY_RCTRL: + CtrlDown = 0; + break; + } } void KeyDown(int key) { switch(key){ + case sk::KEY_LCTRL: + case sk::KEY_RCTRL: + CtrlDown = 1; + break; case sk::KEY_ESC: sk::globals.quit = 1; break; } } +void +MouseBtn(sk::MouseState *mouse) +{ + MouseButtons = mouse->buttons; + RotateLight = !CtrlDown && !!(MouseButtons&1); + TranslateLightXY = CtrlDown && !!(MouseButtons&1); + TranslateLightZ = CtrlDown && !!(MouseButtons&4); +} + +void +MouseMove(sk::MouseState *mouse) +{ + MouseDeltaX = mouse->posx - MouseX; + MouseDeltaY = mouse->posy - MouseY; + MouseX = mouse->posx; + MouseY = mouse->posy; + + if(RotateLight) + LightRotate(-MouseDeltaX, MouseDeltaY); + if(TranslateLightXY) + LightTranslateXY(-MouseDeltaX*0.1f, -MouseDeltaY*0.1f); + if(TranslateLightZ) + LightTranslateZ(-MouseDeltaY*0.1f); +} + 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: - Init(); + Initialize(); return EVENTPROCESSED; case RWINITIALIZE: - return ::InitRW() ? EVENTPROCESSED : EVENTERROR; + return Initialize3D() ? EVENTPROCESSED : EVENTERROR; case PLUGINATTACH: return attachPlugins() ? EVENTPROCESSED : EVENTERROR; case KEYDOWN: @@ -344,6 +335,16 @@ AppEventHandler(sk::Event e, void *param) 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 @@ -352,13 +353,13 @@ AppEventHandler(sk::Event e, void *param) 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); + if(::Camera){ + sk::CameraSize(::Camera, r); + ::Camera->setFOV(FOV, (float)sk::globals.width/sk::globals.height); } break; case IDLE: - Draw(*(float*)param); + Idle(*(float*)param); return EVENTPROCESSED; } return sk::EVENTNOTPROCESSED; diff --git a/tools/lights/main.h b/tools/lights/main.h new file mode 100644 index 0000000..6358f2d --- /dev/null +++ b/tools/lights/main.h @@ -0,0 +1,7 @@ + +extern rw::World *World; +extern rw::Camera *Camera; + +extern rw::V3d Xaxis; +extern rw::V3d Yaxis; +extern rw::V3d Zaxis;