/branches/JSTUDIO_VERSION_2_X/source/Engine/JetEngine/Bsp/jeBSP_HW.cpp
# · C++ · 596 lines · 353 code · 105 blank · 138 comment · 72 complexity · b5d16c433d455918bd6b799d1daca8c7 MD5 · raw file
- /****************************************************************************************/
- /* jeBSP_HW.cpp */
- /* */
- /* Author: Bruno Pettorelli */
- /* Description: HW optimized BSP code based on the John Pollard's */
- /* */
- /* The contents of this file are subject to the Jet3D Public License */
- /* Version 1.02 (the "License"); you may not use this file except in */
- /* compliance with the License. You may obtain a copy of the License at */
- /* http://www.jet3d.com */
- /* */
- /* Software distributed under the License is distributed on an "AS IS" */
- /* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */
- /* the License for the specific language governing rights and limitations */
- /* under the License. */
- /* */
- /* The Original Code is Jet3D, released December 12, 1999. */
- /* Copyright (C) 1996-1999 Eclipse Entertainment, L.L.C. All Rights Reserved */
- /* */
- /****************************************************************************************/
- #include <stdio.h>
- #include <assert.h>
- #include <windows.h>
-
- // Private dependents
- #include "jeBSP._h"
- #include "Ram.h"
- #include "Vec3d.h"
- #include "Errorlog.h"
- #include "Log.h"
- #include "math.h"
- #include "Camera._h"
- // Public dependents
- #include "jeBSP.h"
- #include "jeBSP_HW.h"
- #ifdef _DEBUG
- #define JE_BSP_DEBUG_OUTPUT_LEVEL 1
- //#define JE_BSP_DEBUG_OUTPUT_LEVEL 2
- #else
- #define JE_BSP_DEBUG_OUTPUT_LEVEL 0
- #endif
- //--- Local global statics
- static int32 NumNonVisNodes;
- // extern data for stats purpose - Krouer
- extern int32 NumMakeFaces;
- extern int32 NumMergedFaces;
- extern int32 NumSubdividedFaces;
- // Prototypes
- static jeBoolean jeBSP_HWXF_CreateVertexBuffer(jeBSP* BSP);
- //=======================================================================================
- // jeBSP_Create
- // Create an "empty" BSP tree
- //=======================================================================================
- jeBSP *jeBSP_HWXF_Create(void)
- {
- jeBSP* BSPTree = jeBSP_Create();
- if (BSPTree) {
- BSPTree->HWHelper = NULL;
- BSPTree->HWVertexBuffer = JE_GEOMETRY_BUFFER_NULL_INDEX;
- }
- return BSPTree;
- }
- //=======================================================================================
- // jeBSP_Destroy
- //=======================================================================================
- void jeBSP_HWXF_Destroy(jeBSP **BSPTree)
- {
- // Detach from the engine (if any)
- if ((*BSPTree)->HWHelper)
- {
- if ((*BSPTree)->HWHelper)
- {
- delete (*BSPTree)->HWHelper;
- (*BSPTree)->HWHelper = NULL;
- }
- jeBSP* BSP = *BSPTree;
- jeGeometry_PolyData* pPolyData = NULL;
- while(pPolyData = (jeGeometry_PolyData*)jeChain_GetNextLinkData(BSP->HWPolyDatas, pPolyData))
- {
- jeChain_RemoveLinkData(BSP->HWPolyDatas, pPolyData);
- jeRam_Free(pPolyData);
- }
- jeChain_Destroy(&BSP->HWPolyDatas);
- }
- jeBSP_Destroy(BSPTree);
- }
- //=======================================================================================
- // jeBSP_RebuildGeometry
- // Creates a fresh tree from a list of brushes
- //=======================================================================================
- jeBSP *jeBSP_HWXF_RebuildGeometry(jeBSP *BSP,
- jeChain *BrushChain,
- jeBSP_Options Options,
- jeBSP_Logic Logic,
- jeBSP_LogicBalance LogicBalance)
- {
- jeBSP_Brush *BSPBrushList;
- assert(BSP);
- assert(BrushChain);
- // Destroy any geometry the BSP might have, and reset arrays
- if (!jeBSP_ResetGeometry(BSP))
- return NULL;
- BSPBrushList = NULL;
- // Set some globals
- BSP->Logic = Logic;
- BSP->LogicBalance = LogicBalance;
- BSP->NumBrushes = 0;
- // Create the TopLevel brushes, from the editor jeBrushes...
- BSP->TopBrushes = jeBSP_TopBrushCreateListFromBrushChain(BrushChain, BSP, &BSP->NumBrushes);
- if (!BSP->TopBrushes)
- goto ExitWithError;
- // Create the brushes that will get cut up in the tree
- BSPBrushList = jeBSP_BrushCreateListFromTopBrushList(BSP->TopBrushes, BSP);
-
- if (!BSPBrushList)
- goto ExitWithError;
- // CSG this list
- if (Options & BSP_OPTIONS_CSG_BRUSHES)
- {
- BSPBrushList = jeBSP_BrushCSGList(BSPBrushList, BSP);
- if (!BSPBrushList)
- goto ExitWithError;
- }
- // Now, build the tree
- if (!jeBSP_BuildBSPTree(BSP, &BSPBrushList, Logic, LogicBalance))
- goto ExitWithError;
- // Create portals
- if (!jeBSP_CreatePortals(BSP, JE_TRUE))
- goto ExitWithError;
-
- // Remove hidden leafs
- //if (!jeBSP_RemoveHiddenLeafs(BSP))
- // goto ExitWithError;
- // Use the tree to mark the visible sides
- if (!jeBSP_MarkVisibleTopSides(BSP))
- goto ExitWithError;
- // Merge nodes
- //jeBSPNode_MergeLeafs(BSP->RootNode);
- // Make collision hulls for leafs
- if (!jeBSPNode_UpdateLeafSides_r(BSP->RootNode, BSP))
- goto ExitWithError;
- if (Options & BSP_OPTIONS_MAKE_VIS_AREAS)
- {
- if (!jeBSP_HWXF_Node_MakeFaces_Callr(BSP->RootNode, BSP, JE_FALSE))
- goto ExitWithError;
- if (!jeBSPNode_MakeDrawFaceListOnLeafs_r(BSP->RootNode, BSP))
- goto ExitWithError;
- // We MUST destroy the chain of merged/split faces fragments as soon as we are done with them
- jeBSPNode_DestroyBSPFaces_r(BSP->RootNode, BSP, JE_TRUE);
-
- if (!jeBSP_MakeVisAreas(BSP))
- goto ExitWithError;
- }
- else
- {
- if (!jeBSP_HWXF_Node_MakeFaces_Callr(BSP->RootNode, BSP, JE_TRUE))
- goto ExitWithError;
- }
- if (!jeBSP_UpdateWorldSpaceBox(BSP))
- goto ExitWithError;
- if (!jeBSP_HWXF_CreateVertexBuffer(BSP))
- goto ExitWithError;
- return BSP;
- // Error
- ExitWithError:
- {
- if (BSP->RootNode)
- jeBSPNode_Destroy_r(&BSP->RootNode, BSP);
- if (BSP->TopBrushes)
- jeBSP_TopBrushDestroyList(&BSP->TopBrushes, BSP);
- if (BSPBrushList)
- jeBSP_BrushDestroyList(&BSPBrushList);
- return NULL;
- }
- }
- //=======================================================================================
- // Update lights/faces/brushes
- //=======================================================================================
- //=======================================================================================
- // jeBSP_HWXF_UpdateAll
- //=======================================================================================
- jeBoolean jeBSP_HWXF_UpdateAll(jeBSP *BSP)
- {
- assert(BSP);
- #if (JE_BSP_DEBUG_OUTPUT_LEVEL >= 2)
- OutputDebugString("BEGIN jeBSP_UpdateAll\n");
- #endif
- if (!BSP->RootNode)
- return JE_TRUE;
- bool bUpdate = false;
- if (BSP->HWVertexBuffer == JE_GEOMETRY_BUFFER_NULL_INDEX)
- {
- bUpdate = true;
- }
- if (BSP->UpdateFlags & BSP_UPDATE_FACES)
- {
- if (!jeBSP_MarkVisibleTopSides(BSP))
- return JE_FALSE;
- NumMakeFaces = 0;
- NumMergedFaces = 0;
- NumSubdividedFaces = 0;
- if (!jeBSP_HWXF_Node_MakeFaces_r(BSP->RootNode, BSP, JE_TRUE))
- return JE_FALSE;
- BSP->UpdateFlags &= ~BSP_UPDATE_FACES;
- bUpdate = true;
- }
- //if (BSP->UpdateFlags & BSP_UPDATE_LIGHTS)
- //{
- // if (!jeBSPNode_LightUpdate_r(BSP->RootNode, BSP, BSP->RootNode, JE_FALSE))
- // return JE_FALSE;
- // BSP->UpdateFlags &= ~BSP_UPDATE_LIGHTS;
- //}
- if (bUpdate && !jeBSP_HWXF_CreateVertexBuffer(BSP))
- return JE_FALSE;
- #if (JE_BSP_DEBUG_OUTPUT_LEVEL >= 2)
- OutputDebugString("END jeBSP_UpdateAll\n");
- #endif
- return JE_TRUE;
- }
- //=======================================================================================
- // jeBSP_SetEngine
- //=======================================================================================
- jeBoolean jeBSP_HWXF_SetEngine(jeBSP *BSP, jeEngine *Engine)
- {
- assert(BSP);
- if (Engine == NULL) {
- // Destroy the allocated GeometryBuffer
- DRV_Driver* Driver = jeEngine_GetDriver(BSP->Engine);
- // Delete allocated resource
- if (BSP->HWVertexBuffer != JE_GEOMETRY_BUFFER_NULL_INDEX) {
- Driver->GeometryBuffer_Destroy(BSP->HWVertexBuffer);
- }
- BSP->HWVertexBuffer = JE_GEOMETRY_BUFFER_NULL_INDEX;
- }
- jeBSP_SetEngine(BSP, Engine);
- if (Engine && BSP->HWVertexBuffer == JE_GEOMETRY_BUFFER_NULL_INDEX && BSP->HWHelper != NULL)
- {
- jeErrorLog_AddString(-1, "Generate the Hardware buffer from primitives", NULL);
- jeBSP_HWXF_CreateVertexBuffer(BSP);
- }
- return JE_TRUE;
- }
- //=======================================================================================
- // jeBSP_RenderFrontToBack
- //=======================================================================================
- jeBoolean jeBSP_HWXF_Render(jeBSP *BSP, jeCamera *Camera, jeFrustum *CameraSpaceFrustum, jeFrustum *ModelSpaceFrustum, jeXForm3d *ModelToCameraXForm)
- {
- if (BSP->HWVertexBuffer != JE_GEOMETRY_BUFFER_NULL_INDEX) {
- // Activate the correct geometry buffer
- DRV_Driver* Driver = jeEngine_GetDriver(BSP->Engine);
- Driver->GeometryBuffer_Activate(BSP->HWVertexBuffer);
- /*
- jeVec3d CamPos;
- jeCamera_GetPosition(Camera, &CamPos);
- [00:16] paradox10166: Generate the matrix using the camera position and rotation.
- [00:16] paradox10166: Exactly, grab the XForm.Translation from the camera.
- [00:17] paradox10166: Then use jeXForm3d_GetEulerAngles() on the Camera XForm.
- [00:20] paradox10166: Then build the view transform using this method:http://www.toymaker.info/Games/html/camera.html
- */
- // Set the Matrices
- #pragma message ("Krouer: Need help here to set the correct matrices")
- // Reset the matrice set
- jeXForm3d identity;
- jeXForm3d cameraXForm;
- jeXForm3d_SetIdentity(&identity);
- jeCamera_GetXForm(Camera, &cameraXForm);
- //cameraXForm.AZ = -cameraXForm.AZ;
- //cameraXForm.BZ = -cameraXForm.BZ;
- //cameraXForm.CZ = -cameraXForm.CZ;
- //jeVec3d_Scale(&cameraXForm.Translation, 1.5, &cameraXForm.Translation);
- //Driver->SetMatrix(JE_XFORM_TYPE_VIEW, ModelToCameraXForm);
- //Driver->SetMatrix(JE_XFORM_TYPE_WORLD, &identity);
- Driver->SetMatrix(JE_XFORM_TYPE_VIEW, &cameraXForm);
- Driver->SetMatrix(JE_XFORM_TYPE_WORLD, &BSP->WorldToModelXForm);
-
- // Call the rendering for each primitive I have
- if (BSP->HWPolyDatas) {
- jeGeometry_PolyData* pPolyData = NULL;
- while (pPolyData = (jeGeometry_PolyData*)jeChain_GetNextLinkData(BSP->HWPolyDatas, pPolyData))
- {
- Driver->GeometryBuffer_DrawPolyData(pPolyData);
- }
- }
- Driver->SetMatrix(JE_XFORM_TYPE_VIEW, &identity);
- Driver->SetMatrix(JE_XFORM_TYPE_WORLD, &identity);
- if (BSP->AreaChain)
- {
- jeChain_Link *Link;
- for (Link = jeChain_GetFirstLink(BSP->AreaChain); Link; Link = jeChain_LinkGetNext(Link))
- {
- jeBSPNode_Area *Area = (jeBSPNode_Area*)jeChain_LinkGetLinkData(Link);;
- jeChain_Link *Link2;
- // The Area is visible, render all objects inside the area
- // NOTE - For now, objects only live in one area at a time, so we
- // always render them. As soon as they are allowed to live in more than
- // one area, we will have to take this into account, and make sure we only render
- // them once...
- for (Link2 = jeChain_GetFirstLink(Area->ObjectChain); Link2; Link2 = jeChain_LinkGetNext(Link2))
- {
- jeObject *Object = (jeObject*)jeChain_LinkGetLinkData(Link2);
- jeObject_Type objectType = jeObject_GetType(Object);
- switch (objectType)
- {
- case JE_OBJECT_TYPE_LIGHT:
- // Do nothing
- break;
- case JE_OBJECT_TYPE_TERRAIN:
- // fall down to actor process
- case JE_OBJECT_TYPE_ACTOR:
- // set the flag visibility to true
- jeObject_SetRenderNextPass(Object, JE_TRUE);
- break;
- default:
- // Render the object
- if (!jeObject_Render(Object, BSP->World, BSP->Engine, Camera, CameraSpaceFrustum, 0))
- return JE_FALSE;
- break;
- }
- }
- }
- }
- else // Render every object, since there is no areas...
- {
- jeChain_Link *Link;
- for (Link = jeChain_GetFirstLink(BSP->BSPObjectChain); Link; Link = jeChain_LinkGetNext(Link))
- {
- jeBSP_Object *BSPObject = (jeBSP_Object*)jeChain_LinkGetLinkData(Link);
- // Render the object
- if (!jeObject_Render(BSPObject->Object, BSP->World, BSP->Engine, Camera, CameraSpaceFrustum, 0))
- return JE_FALSE;
- }
- }
- return JE_TRUE;
- }
- return jeBSP_RenderFrontToBack(BSP, Camera, CameraSpaceFrustum, ModelSpaceFrustum, ModelToCameraXForm);
- }
- //=======================================================================================
- // jeBSP_RenderAndVis
- //=======================================================================================
- jeBoolean jeBSP_HWXF_RenderAndVis(jeBSP *BSP, jeCamera *Camera, jeFrustum *Frustum)
- {
- jeFrustum ModelSpaceFrustum;
- jeXForm3d ModelToCameraXForm, CameraToModelXForm;
- BSP->DebugInfo.NumVisibleAreas = 0;
- jeXForm3d_Multiply(jeCamera_XForm(Camera), &BSP->ModelToWorldXForm, &ModelToCameraXForm);
- jeXForm3d_GetTranspose(&ModelToCameraXForm, &CameraToModelXForm);
- // Transform Frustum from camera space to model space
- jeFrustum_Transform(Frustum, &CameraToModelXForm, &ModelSpaceFrustum);
- if (!jeBSP_HWXF_UpdateAll(BSP))
- return JE_FALSE;
- if (!jeBSP_VisFrame(BSP, Camera, &ModelSpaceFrustum))
- return JE_FALSE;
- if (!jeBSP_UpdateDLights(BSP))
- return JE_FALSE;
- if (!jeBSP_UpdateObjects(BSP))
- return JE_FALSE;
- // Render the models BSP tree
- if (!jeBSP_HWXF_Render(BSP, Camera, Frustum, &ModelSpaceFrustum, &CameraToModelXForm /*/(jeXForm3d*) jeCamera_XForm(Camera) /*&ModelToCameraXForm*/))
- return JE_FALSE;
- return JE_TRUE;
- }
- //=======================================================================================
- // jeBSP_RebuildFaces
- //=======================================================================================
- jeBoolean jeBSP_HWXF_RebuildFaces(jeBSP *BSPTree)
- {
- if (!BSPTree->RootNode)
- return JE_TRUE;
- jeBSP_HWXF_Node_RebuildFaces_r(BSPTree->RootNode, BSPTree);
- // Use the tree to mark the visible sides
- if (!jeBSP_MarkVisibleTopSides(BSPTree))
- return JE_FALSE;
- if (!jeBSP_HWXF_Node_MakeFaces_Callr(BSPTree->RootNode, BSPTree, JE_TRUE))
- return JE_FALSE;
- return JE_TRUE;
- }
- void JETCC jeBSP_HWXF_ResetListener(void *Context)
- {
- jeBSP* BSP = (jeBSP*) Context;
- BSP->HWVertexBuffer = JE_GEOMETRY_BUFFER_NULL_INDEX;
- }
- //=======================================================================================
- // jeBSP_HWXF_CreateVertexBuffer
- // Create a vertex buffer and initialise the Geometry of all jeBSP_Brush
- //=======================================================================================
- static jeBoolean jeBSP_HWXF_CreateVertexBuffer(jeBSP* BSP)
- {
- // Like we copy the same amount of data in the vert array and in the HWHelpers
- SHWInfoData globalInfo;
- // Time to recover the primitive
- if (BSP->HWPolyDatas) {
- jeGeometry_PolyData* pPolyData = NULL;
- while(pPolyData = (jeGeometry_PolyData*)jeChain_GetNextLinkData(BSP->HWPolyDatas, pPolyData))
- {
- jeChain_RemoveLinkData(BSP->HWPolyDatas, pPolyData);
- jeRam_Free(pPolyData);
- }
- jeChain_Destroy(&BSP->HWPolyDatas);
- }
- BSP->HWPolyDatas = jeChain_Create();
- BSP->HWHelper->GeneratePrimitive(BSP, &globalInfo);
- if (BSP->Engine)
- {
- // Engine linked with the BSP so we can do something now
- DRV_Driver* Driver = jeEngine_GetDriver(BSP->Engine);
- // Delete allocated resource
- if (BSP->HWVertexBuffer != JE_GEOMETRY_BUFFER_NULL_INDEX) {
- Driver->GeometryBuffer_Destroy(BSP->HWVertexBuffer);
- }
- // Create a new geometry buffer
- BSP->HWVertexBuffer = Driver->GeometryBuffer_Create(globalInfo.vertices.size(), globalInfo.indices.size(), JE_FALSE, jeBSP_HWXF_ResetListener, BSP);
- // Move the jeHWVertex std::vector to a C array
- jeHWVertex* pHWVertices = JE_RAM_ALLOCATE_ARRAY(jeHWVertex, globalInfo.vertices.size());
- for (uint32 idx = 0; idx<globalInfo.vertices.size(); idx++) {
- pHWVertices[idx] = globalInfo.vertices[idx];
- }
- // Copy the array to the Driver and free it
- Driver->GeometryBuffer_AddVertices(BSP->HWVertexBuffer, pHWVertices, globalInfo.vertices.size(), JE_TRUE);
- jeRam_Free(pHWVertices);
- // Move the Indice std::vector to C array
- uint16* pIndices = JE_RAM_ALLOCATE_ARRAY(uint16, globalInfo.indices.size());
- for (uint32 idx = 0; idx<globalInfo.indices.size(); idx++) {
- pIndices[idx] = globalInfo.indices[idx];
- }
- // Copy the array to the Driver and free it
- Driver->GeometryBuffer_AddIndices(BSP->HWVertexBuffer, pIndices, globalInfo.indices.size(), JE_TRUE);
- jeRam_Free(pIndices);
- }
- return JE_TRUE;
- }
- //=======================================================================================
- // CBSP_HWHelper class implementation
- //=======================================================================================
- CBSP_HWHelper::CBSP_HWHelper()
- {
- }
- CBSP_HWHelper::~CBSP_HWHelper()
- {
- }
- /***
- Append per material the poly and the indices
- */
- jeBoolean CBSP_HWHelper::Append(jeMaterialSpec *pMat, uint32 size, jeHWVertex* pVertices, triangle_stripper::indices& indices)
- {
- SHWInfoData& indexData = m_materialMap[pMat];
- // Store for the addition the starting index
- int32 startVertex = indexData.vertices.size();
- // Record the index in the associated vertex array
- for (int32 i=0; i<indices.size();i++) {
- //indices[i]+=indexData.startVertex;
- indices[i]+=startVertex;
- indexData.indices.push_back(indices[i]);
- }
- for (int32 i=0; i<size; i++, pVertices++) {
- indexData.vertices.push_back(*pVertices);
- }
- return JE_TRUE;
- }
- SHWInfoData& CBSP_HWHelper::GetVertInfo(jeMaterialSpec* pMat)
- {
- return m_materialMap[pMat];
- }
- // Generate Geometry_PolyData per material and do the stripping when wanted
- void CBSP_HWHelper::GeneratePrimitive(jeBSP* BSP, SHWInfoData* pGlobalInfo)
- {
- SHWInfoDataMap::iterator it = m_materialMap.begin();
- while (it != m_materialMap.end())
- {
- jeGeometry_PolyData* pPolyData = JE_RAM_ALLOCATE_STRUCT(jeGeometry_PolyData);
- pPolyData->BaseVertexIndex = 0;
- pPolyData->PrimitiveType = JE_PRIMITIVE_TYPE_TRIANGLELIST;
- // Fill the material spec use
- pPolyData->Material = it->first;
- // Fill the vertex start point
- SHWInfoData& localInfo = it->second;
- pPolyData->StartVertex = pGlobalInfo->vertices.size();
- pPolyData->StartIndex = pGlobalInfo->indices.size();
- pPolyData->NumVertices = localInfo.vertices.size();
- pPolyData->NumPolys = localInfo.indices.size() / 3; // Triangle list for now
- for (uint32 i=0; i<localInfo.indices.size(); i++) {
- pGlobalInfo->indices.push_back(localInfo.indices[i] + pPolyData->StartVertex);
- }
- for (uint32 i=0; i<localInfo.vertices.size(); i++) {
- pGlobalInfo->vertices.push_back(localInfo.vertices[i]);
- }
- // Add the poly data to the vertice stuff
- jeChain_AddLinkData(BSP->HWPolyDatas, pPolyData);
- // Go to next material
- it++;
- }
- }
- void CBSP_HWHelper::Reset()
- {
- m_materialMap.erase(m_materialMap.begin(), m_materialMap.end());
- m_materialMap.clear();
- }