/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : ww3d * * * * $Archive:: /Commando/Code/ww3d2/dx8renderer.h $* * * * Original Author:: Jani Penttinen * * * * $Author:: Greg_h $* * * * $Modtime:: 2/28/02 5:34p $* * * * $Revision:: 30 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #if defined(_MSC_VER) #pragma once #endif #ifndef DX8_RENDERER_H #define DX8_RENDERER_H #include "always.h" #include "wwstring.h" #include "simplevec.h" #include "refcount.h" #include "vector.h" #include "dx8list.h" #include "shader.h" #include "dx8wrapper.h" #include "hashtemplate.h" class IndexBufferClass; class VertexBufferClass; class DX8RenderTypeArrayClass; class MeshClass; class MeshModelClass; class DX8PolygonRendererClass; class Vertex_Split_Table; class DX8FVFCategoryContainer; class DecalMeshClass; class MaterialPassClass; class MatPassTaskClass; class PolyRenderTaskClass; class TextureClass; class VertexMaterialClass; class CameraClass; #define RECORD_RENDER(I,P) render_stats[I].count++; render_stats[I].polys+=P; /** ** DX8TextureCategoryClass ** This class is used for each Material-Texture-Shader combination that is encountered during rendering. ** Each polygon_renderer that uses the same 'TextureCategory' will be linked to the 'TextureCategory' object. ** Then, all polygons will be rendered in 'TextureCategory' batches to reduce the number of stage changes ** (and most importantly, texture changes) that we cause in DX8. */ class DX8TextureCategoryClass : public MultiListObjectClass { int pass; TextureClass * textures[MAX_TEXTURE_STAGES]; ShaderClass shader; VertexMaterialClass * material; DX8PolygonRendererList PolygonRendererList; DX8FVFCategoryContainer* container; PolyRenderTaskClass * render_task_head; // polygon renderers queued for rendering public: DX8TextureCategoryClass(DX8FVFCategoryContainer* container,TextureClass** textures, ShaderClass shd, VertexMaterialClass* mat,int pass); ~DX8TextureCategoryClass(); void Add_Render_Task(DX8PolygonRendererClass * p_renderer,MeshClass * p_mesh); void Render(void); bool Anything_To_Render() { return (render_task_head != NULL); } void Clear_Render_List() { render_task_head = NULL; } TextureClass * Peek_Texture(int stage) { return textures[stage]; } const VertexMaterialClass * Peek_Material() { return material; } ShaderClass Get_Shader() { return shader; } DX8PolygonRendererList& Get_Polygon_Renderer_List() { return PolygonRendererList; } unsigned Add_Mesh( Vertex_Split_Table& split_buffer, unsigned vertex_offset, unsigned index_offset, IndexBufferClass* index_buffer, unsigned pass); void Log(bool only_visible); void Remove_Polygon_Renderer(DX8PolygonRendererClass* p_renderer); void Add_Polygon_Renderer(DX8PolygonRendererClass* p_renderer,DX8PolygonRendererClass* add_after_this=NULL); DX8FVFCategoryContainer * Get_Container(void) { return container; } }; // ---------------------------------------------------------------------------- /** ** DX8FVFCategoryContainer */ class DX8FVFCategoryContainer : public MultiListObjectClass { public: enum { MAX_PASSES=4 }; protected: TextureCategoryList texture_category_list[MAX_PASSES]; TextureCategoryList visible_texture_category_list[MAX_PASSES]; MatPassTaskClass * visible_matpass_head; MatPassTaskClass * visible_matpass_tail; IndexBufferClass * index_buffer; int used_indices; unsigned FVF; unsigned passes; unsigned uv_coordinate_channels; bool sorting; bool AnythingToRender; bool AnyDelayedPassesToRender; void Generate_Texture_Categories(Vertex_Split_Table& split_table,unsigned vertex_offset); void DX8FVFCategoryContainer::Insert_To_Texture_Category( Vertex_Split_Table& split_table, TextureClass** textures, VertexMaterialClass* mat, ShaderClass shader, int pass, unsigned vertex_offset); inline bool Anything_To_Render() { return AnythingToRender; } inline bool Any_Delayed_Passes_To_Render() { return AnyDelayedPassesToRender; } void Render_Procedural_Material_Passes(void); DX8TextureCategoryClass* Find_Matching_Texture_Category( TextureClass* texture, unsigned pass, unsigned stage, DX8TextureCategoryClass* ref_category); DX8TextureCategoryClass* Find_Matching_Texture_Category( VertexMaterialClass* vmat, unsigned pass, DX8TextureCategoryClass* ref_category); public: DX8FVFCategoryContainer(unsigned FVF,bool sorting); virtual ~DX8FVFCategoryContainer(); static unsigned Define_FVF(MeshModelClass* mmc,unsigned int * user_lighting,bool enable_lighting); bool Is_Sorting() const { return sorting; } void Change_Polygon_Renderer_Texture( DX8PolygonRendererList& polygon_renderer_list, TextureClass* texture, TextureClass* new_texture, unsigned pass, unsigned stage); void Change_Polygon_Renderer_Material( DX8PolygonRendererList& polygon_renderer_list, VertexMaterialClass* vmat, VertexMaterialClass* new_vmat, unsigned pass); void Remove_Texture_Category(DX8TextureCategoryClass* tex_category); virtual void Render(void)=0; virtual void Add_Mesh(MeshClass* mmc)=0; virtual void Log(bool only_visible)=0; virtual bool Check_If_Mesh_Fits(MeshModelClass* mmc)=0; inline unsigned Get_FVF() const { return FVF; } inline void Add_Visible_Texture_Category(DX8TextureCategoryClass * tex_category,int pass) { WWASSERT(pass::Get_Hash_Value(const MeshRegKeyStruct& key) { unsigned int hval = (unsigned int)(key.Model) + (unsigned int)(key.UserLighting); hval = hval + (hval>>5) + (hval>>10) + (hval >> 20); return hval; } /** ** DX8MeshRendererClass ** This object is controller for the entire DX8 mesh rendering system. It organizes mesh ** fragments into groups based on FVF, texture, and material. During rendering, a list of ** the visible mesh fragments is composed and rendered. There is a global instance of this ** class called TheDX8MeshRenderer that should be used for all mesh rendering. */ class DX8MeshRendererClass { public: DX8MeshRendererClass(); ~DX8MeshRendererClass(); void Init(); void Shutdown(); void Flush(); void Clear_Pending_Delete_Lists(); void Log_Statistics_String(bool only_visible); static void Request_Log_Statistics(); void Register_Mesh_Type(MeshClass* mesh); void Unregister_Mesh_Type(MeshClass* mesh); void Set_Camera(CameraClass* cam) { camera=cam; } CameraClass * Peek_Camera(void) { return camera; } void Add_To_Render_List(DecalMeshClass * decalmesh); // Enable or disable lighting on all objects inserted from now on. (Doesn't affect the objects that are already in the lists) void Enable_Lighting(bool enable) { enable_lighting=enable; } // This should be called at the beginning of a game or menu or after a major modifications to the scene... void Invalidate(); protected: void Render_Decal_Meshes(void); bool enable_lighting; CameraClass * camera; SimpleDynVecClass texture_category_container_lists_rigid; FVFCategoryList * texture_category_container_list_skin; DecalMeshClass * visible_decal_meshes; HashTemplateClass _RegisteredMeshTable; }; extern DX8MeshRendererClass TheDX8MeshRenderer; #endif