Rev 136 | Rev 164 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 1 | pmbaty | 1 | // render.cpp | 
        
| 2 | |||
| 3 | // thanks ChaotikMind for optimizing the engine a bit :) | 
        ||
| 4 | |||
| 5 | #include "common.h" | 
        ||
| 6 | |||
| 7 | |||
| 8 | // note: DirectX requires a C++ compiler. | 
        ||
| 9 | #include "DirectX9/Include/d3d9.h" | 
        ||
| 10 | #include "DirectX9/Include/d3dx9.h" | 
        ||
| 11 | |||
| 12 | // include the Direct3D library files | 
        ||
| 13 | #pragma comment (lib, "DirectX9/Lib/x86/d3d9.lib") | 
        ||
| 14 | #pragma comment (lib, "DirectX9/Lib/x86/d3dx9.lib") | 
        ||
| 15 | |||
| 16 | |||
| 17 | // handy macro to print a chatter channel reply | 
        ||
| 18 | #define PRINT_CCREPLY(ccreply) \ | 
        ||
| 19 | { \ | 
        ||
| 124 | pmbaty | 20 |    Render_wprintf (rect.right * 100.0f / initial_width, 100 - combinedheight_percent, (initial_width - rect.right) * 100.0f / initial_width, ALIGN_LEFT, ALIGN_TOP, ALIGN_LEFT, \ | 
        
| 1 | pmbaty | 21 |                    chat_fontindex, (ccreply)->color, &rect, \ | 
        
| 22 |                    L"["); \ | 
        ||
| 124 | pmbaty | 23 |    Render_wprintf (rect.right * 100.0f / initial_width, 100 - combinedheight_percent, (initial_width - rect.right) * 100.0f / initial_width, ALIGN_LEFT, ALIGN_TOP, ALIGN_LEFT, \ | 
        
| 1 | pmbaty | 24 |                    chat_fontindex, RGBA_TO_RGBACOLOR (159, 159, 159, RGBACOLOR_ALPHA ((ccreply)->color)), &rect, \ | 
        
| 25 |                    (ccreply)->channelname); \ | 
        ||
| 124 | pmbaty | 26 |    Render_wprintf (rect.right * 100.0f / initial_width, 100 - combinedheight_percent, (initial_width - rect.right) * 100.0f / initial_width, ALIGN_LEFT, ALIGN_TOP, ALIGN_LEFT, \ | 
        
| 1 | pmbaty | 27 |                    chat_fontindex, (ccreply)->color, &rect, \ | 
        
| 28 |                    L"] "); /* closing bracket + non-breakable space */ \ | 
        ||
| 124 | pmbaty | 29 |    Render_wprintf (rect.right * 100.0f / initial_width, 100 - combinedheight_percent, (initial_width - rect.right) * 100.0f / initial_width, ALIGN_LEFT, ALIGN_TOP, ALIGN_LEFT, \ | 
        
| 1 | pmbaty | 30 |                    chat_fontindex, RGBA_TO_RGBACOLOR (159, 159, 159, RGBACOLOR_ALPHA ((ccreply)->color)), &rect, \ | 
        
| 31 |                    (ccreply)->nickname); \ | 
        ||
| 124 | pmbaty | 32 |    Render_wprintf (rect.right * 100.0f / initial_width, 100 - combinedheight_percent, (initial_width - rect.right) * 100.0f / initial_width, ALIGN_LEFT, ALIGN_TOP, ALIGN_LEFT, \ | 
        
| 1 | pmbaty | 33 |                    chat_fontindex, (ccreply)->color, &rect, \ | 
        
| 34 |                    L": "); /* colon + non-breakable space */ \ | 
        ||
| 35 |    if ((ccreply)->text != NULL) \ | 
        ||
| 124 | pmbaty | 36 |       Render_wprintf (rect.right * 100.0f / initial_width, 100 - combinedheight_percent, (initial_width - rect.right) * 100.0f / initial_width, ALIGN_LEFT, ALIGN_TOP, ALIGN_LEFT, \ | 
        
| 1 | pmbaty | 37 |                       chat_fontindex, (ccreply)->color, &rect, \ | 
        
| 38 |                       (ccreply)->text); \ | 
        ||
| 39 | } | 
        ||
| 40 | |||
| 41 | |||
| 42 | // handy macro to draw a GUI button | 
        ||
| 43 | #define DRAW_BUTTON_IF_NEEDED(button) \ | 
        ||
| 44 | { \ | 
        ||
| 45 |    if ((button).state != 0) \ | 
        ||
| 124 | pmbaty | 46 |    { \ | 
        
| 1 | pmbaty | 47 |       Render_DrawSprite (&sprites[(button).sprite_index], (button).left, (button).top, (button).width, (button).height, ((button).state == 2 ? 0xFF : 0x7F)); \ | 
        
| 124 | pmbaty | 48 |       if ((button).text[0] != 0) \ | 
        
| 49 |          Render_wprintf ((button).left + (button).width / 2.0f, (button).top + (button).height / 2.0f, (button).width, ALIGN_CENTER, ALIGN_CENTER, ALIGN_CENTER, chat_fontindex, D3DCOLOR_ARGB (255, 255, 255, /*alpha*/ ((button).state == 2 ? 0xFF : 0x7F)), NULL, (button).text); \ | 
        ||
| 50 |    } \ | 
        ||
| 1 | pmbaty | 51 | } | 
        
| 52 | |||
| 53 | |||
| 54 | // handy macro to draw a GUI text | 
        ||
| 55 | #define DRAW_TEXT_IF_NEEDED(text) \ | 
        ||
| 56 | { \ | 
        ||
| 57 |    if ((text).is_displayed) \ | 
        ||
| 58 |    { \ | 
        ||
| 124 | pmbaty | 59 |       Render_wprintf ((text).xpos_percent, (text).ypos_percent, \ | 
        
| 60 |                       (text).maxwidth_percent, (text).horizontal_align, (text).vertical_align, (text).text_align, (text).font_index, \ | 
        ||
| 1 | pmbaty | 61 |                       ((text).want_fade ? \ | 
        
| 62 |                        RGBACOLOR_SETALPHA ((text).color, \ | 
        ||
| 63 |                                            (((text).appear_time + (text).disappear_time) * 0.5f > current_time ? \ | 
        ||
| 64 |                                            /* fading in  */ (int) FadeFloat (0, RGBACOLOR_ALPHA ((text).color), (text).appear_time, (text).appear_time + 0.5f) : \ | 
        ||
| 65 |                                            /* fading out */ (int) FadeFloat (RGBACOLOR_ALPHA ((text).color), 0, (text).disappear_time - 3.0f, (text).disappear_time))) : \ | 
        ||
| 66 |                        (text).color), \ | 
        ||
| 67 |                       NULL, (text).buffer); \ | 
        ||
| 68 |       if ((text).disappear_time < current_time) \ | 
        ||
| 69 |          (text).is_displayed = false; \ | 
        ||
| 70 |    } \ | 
        ||
| 71 | } | 
        ||
| 72 | |||
| 73 | |||
| 74 | #pragma pack(push,1) | 
        ||
| 75 | |||
| 76 | // definition for a vector | 
        ||
| 77 | typedef struct vector_s  | 
        ||
| 78 | { | 
        ||
| 79 | float x; // X component  | 
        ||
| 80 | float y; // Y component  | 
        ||
| 81 | float z; // Z component  | 
        ||
| 82 | } vector_t;  | 
        ||
| 83 | |||
| 84 | |||
| 85 | // definition for a texture coordinates pair | 
        ||
| 86 | typedef struct texcoord_s  | 
        ||
| 87 | { | 
        ||
| 88 | float u; // X coordinate of the texture point this vertex corresponds to  | 
        ||
| 89 | float v; // Y coordinate of the texture point this vertex corresponds to  | 
        ||
| 90 | } texcoord_t;  | 
        ||
| 91 | |||
| 92 | |||
| 93 | // definition for a vertex (must be in that order for Direct3D) | 
        ||
| 94 | typedef struct vertex_s  | 
        ||
| 95 | { | 
        ||
| 96 | vector_t position; // position in space  | 
        ||
| 97 | vector_t normal; // coordinates of the unary normal vector of the plane this vertex is on (for illumination)  | 
        ||
| 98 | texcoord_t texcoord; // coordinates of the texture point this vertex corresponds to  | 
        ||
| 99 | } vertex_t;  | 
        ||
| 100 | |||
| 101 | #pragma pack(pop) | 
        ||
| 102 | |||
| 103 | |||
| 104 | // definition for a reflected object (qsort array element to sort reflections by distance) | 
        ||
| 105 | typedef struct reflectedobject_s  | 
        ||
| 106 | { | 
        ||
| 107 | sceneobject_t *object; // pointer to the scene object  | 
        ||
| 108 | float distance; // distance to viewer camera  | 
        ||
| 109 | } reflectedobject_t;  | 
        ||
| 110 | |||
| 111 | |||
| 112 | // definition for a material (light reflection type) | 
        ||
| 113 | typedef struct material_s  | 
        ||
| 114 | { | 
        ||
| 115 | wchar_t name[32]; // material name  | 
        ||
| 116 | float ambient; // ambient reflection value ranging from 0 to 1  | 
        ||
| 117 | float diffuse; // diffuse reflection value ranging from 0 to 1  | 
        ||
| 118 | float emissive; // emissive reflection value ranging from 0 to 1  | 
        ||
| 119 | float specular; // specular reflection value ranging from 0 to 1  | 
        ||
| 120 | float shininess; // shininess (specular factor)  | 
        ||
| 121 | float transparency; // transparency value ranging from 0 (fully transparent) to 1 (opaque)  | 
        ||
| 122 | } material_t;  | 
        ||
| 123 | |||
| 124 | |||
| 125 | // definition for a mesh | 
        ||
| 126 | typedef struct mesh_s  | 
        ||
| 127 | { | 
        ||
| 128 | unsigned long hash; // basic content hash, to avoid duplicates  | 
        ||
| 129 | unsigned long vertex_format;  | 
        ||
| 130 | IDirect3DVertexBuffer9 *d3dvertices; // handled opaquely by Direct3D  | 
        ||
| 131 | int vertice_size;  | 
        ||
| 132 | int vertice_count;  | 
        ||
| 133 | bool is_indexed; // set to TRUE if this mesh has an index buffer  | 
        ||
| 134 | IDirect3DIndexBuffer9 *d3dindices; // handled opaquely by Direct3D  | 
        ||
| 135 | int indice_size;  | 
        ||
| 136 | int indice_count;  | 
        ||
| 137 | } mesh_t;  | 
        ||
| 138 | |||
| 139 | |||
| 140 | // definition for a texture | 
        ||
| 141 | typedef struct texture_s  | 
        ||
| 142 | { | 
        ||
| 143 | unsigned long hash; // basic content hash, to avoid duplicates  | 
        ||
| 144 | int width;  | 
        ||
| 145 | int height;  | 
        ||
| 146 | IDirect3DTexture9 *texture;  | 
        ||
| 147 | } texture_t;  | 
        ||
| 148 | |||
| 149 | |||
| 150 | // definition for a font | 
        ||
| 151 | typedef struct font_s  | 
        ||
| 152 | { | 
        ||
| 153 | unsigned long pathname_hash;  | 
        ||
| 154 | ID3DXFont *font;  | 
        ||
| 155 | } font_t;  | 
        ||
| 156 | |||
| 157 | |||
| 158 | // definition for a sprite | 
        ||
| 159 | typedef struct sprite_s  | 
        ||
| 160 | { | 
        ||
| 161 | unsigned long hash; // basic content hash, to avoid duplicates  | 
        ||
| 162 | ID3DXSprite *sprite;  | 
        ||
| 163 | int texture_index;  | 
        ||
| 164 | } sprite_t;  | 
        ||
| 165 | |||
| 166 | |||
| 167 | // global variables used in this module only | 
        ||
| 168 | static IDirect3D9 *d3d = NULL; // our Direct3D interface  | 
        ||
| 169 | static IDirect3DDevice9 *d3ddev = NULL; // the device class  | 
        ||
| 170 | |||
| 171 | static material_t *materials = NULL;  | 
        ||
| 172 | static int material_count = 0;  | 
        ||
| 173 | static texture_t *textures = NULL;  | 
        ||
| 174 | static int texture_count = 0;  | 
        ||
| 175 | static mesh_t *meshes = NULL;  | 
        ||
| 176 | static int mesh_count = 0;  | 
        ||
| 177 | static font_t *fonts = NULL;  | 
        ||
| 178 | static int font_count = 0;  | 
        ||
| 179 | static sprite_t *sprites = NULL;  | 
        ||
| 180 | static int sprite_count = 0;  | 
        ||
| 181 | static const float fov_value = 45.0f; // field of view width, in degrees  | 
        ||
| 182 | static const float viewdist_near = 1.0f; // nearest view plane distance  | 
        ||
| 183 | static const float viewdist_far = 200.0f; // farthest view plane distance  | 
        ||
| 6 | pmbaty | 184 | static int initial_width = 0; // initial width of the render surface, in pixels (typically equal to the max displayable size)  | 
        
| 185 | static int initial_height = 0; // initial height of the render surface, in pixels (typically equal to the max displayable size)  | 
        ||
| 1 | pmbaty | 186 | static float current_width = 0.0f; // current width of the client area on which the render surface is rendered, in pixels  | 
        
| 187 | static float current_height = 0.0f; // current height of the client area on which the render surface is rendered, in pixels  | 
        ||
| 188 | static D3DCOLOR ambient_light;  | 
        ||
| 189 | static vector_t camera_position;  | 
        ||
| 131 | pmbaty | 190 | static vector_t scene_lookatpoint = { 0.0f, 0.0f, 0.0f };  | 
        
| 1 | pmbaty | 191 | static const vector_t upwards_direction = { 0.0f, 0.0f, 1.0f };  | 
        
| 192 | static int best_supported_filter;  | 
        ||
| 5 | pmbaty | 193 | static bool is_fsaa_supported = false;  | 
        
| 1 | pmbaty | 194 | |
| 195 | static wchar_t printf_buffer[0xffff];  | 
        ||
| 196 | |||
| 197 | |||
| 198 | // prototypes of functions used in this module only | 
        ||
| 199 | static bool Render_LoadMesh_X (mesh_t *mesh, const wchar_t *xfile_pathname);  | 
        ||
| 200 | static bool Render_LoadMesh_Obj (mesh_t *mesh, const wchar_t *objfile_pathname);  | 
        ||
| 201 | static void Render_DrawSceneObjectReflection (sceneobject_t *sceneobject);  | 
        ||
| 202 | static void Render_DrawSceneObject (sceneobject_t *sceneobject);  | 
        ||
| 203 | static void Render_DrawSceneTile (sceneobject_t *sceneobject);  | 
        ||
| 204 | static void Render_DrawSprite (sprite_t *sprite, float x_percent, float y_percent, float width_percent, float height_percent, int alpha);  | 
        ||
| 124 | pmbaty | 205 | static void Render_GetTextBoundaries (float maxwidth_percent, int font_id, wchar_t *text, RECT *rect);  | 
        
| 206 | static void Render_wprintf (float x_percent, float y_percent, float maxwidth_percent, int horiz_align, int vert_align, int text_align, int font_id, unsigned long color_rgba, RECT *out_rect, const wchar_t *fmt, ...);  | 
        ||
| 1 | pmbaty | 207 | static float DistanceToCamera (float x, float y, float z);  | 
        
| 208 | static float FadeFloat (float from, float to, float start_time, float end_time);  | 
        ||
| 209 | static unsigned long HashString (const wchar_t *string_buffer);  | 
        ||
| 210 | static unsigned long HashFile (const wchar_t *file_pathname);  | 
        ||
| 211 | static void ResolveWildcard (wchar_t *file_pathname, wchar_t *extensions_separated_by_bars);  | 
        ||
| 212 | static int SortReflectedObjects (const void *object1, const void *object2);  | 
        ||
| 213 | |||
| 214 | |||
| 116 | pmbaty | 215 | bool Render_Init (const wchar_t *fmt, ...)  | 
        
| 1 | pmbaty | 216 | { | 
        
| 217 |    // this function sets up and initializes Direct3D | 
        ||
| 218 | |||
| 116 | pmbaty | 219 | static wchar_t splashscreen_pathname[MAX_PATH];  | 
        
| 1 | pmbaty | 220 | static wchar_t *default_materialname = L"default";  | 
        
| 116 | pmbaty | 221 | va_list argptr;  | 
        
| 1 | pmbaty | 222 | |
| 223 |    D3DCAPS9 device_capabilities; | 
        ||
| 224 | unsigned long behaviour_flags;  | 
        ||
| 5 | pmbaty | 225 | unsigned long multisample_quality_count;  | 
        
| 1 | pmbaty | 226 |    D3DPRESENT_PARAMETERS d3dpp; | 
        
| 2 | pmbaty | 227 | wchar_t errorfile_path[MAX_PATH];  | 
        
| 1 | pmbaty | 228 | wchar_t line_buffer[256];  | 
        
| 229 |    material_t material; | 
        ||
| 2 | pmbaty | 230 |    HRESULT ret; | 
        
| 1 | pmbaty | 231 |    RECT rect; | 
        
| 6 | pmbaty | 232 |    RECT viewport_rect; | 
        
| 1 | pmbaty | 233 | FILE *fp;  | 
        
| 234 | |||
| 116 | pmbaty | 235 |    // concatenate all the arguments in one string | 
        
| 236 | va_start (argptr, fmt);  | 
        ||
| 237 | wvsprintf (splashscreen_pathname, fmt, argptr);  | 
        ||
| 238 | va_end (argptr);  | 
        ||
| 239 | |||
| 1 | pmbaty | 240 |    // create the Direct3D interface | 
        
| 241 | d3d = Direct3DCreate9 (D3D_SDK_VERSION);  | 
        ||
| 242 | |||
| 243 |    // get hardware capabilities | 
        ||
| 244 | if (FAILED (d3d->GetDeviceCaps (D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &device_capabilities)))  | 
        ||
| 245 |    { | 
        ||
| 246 | MessageBox (NULL, LOCALIZE (L"Error_CouldNotCreateD3DDevGetDeviceCapsFailed"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK);  | 
        ||
| 11 | pmbaty | 247 | terminate_everything = true; // this is a fatal error  | 
        
| 1 | pmbaty | 248 | return (false);  | 
        
| 249 |    } | 
        ||
| 250 | |||
| 251 |    // grab info from that and adjust our D3D settings | 
        ||
| 252 | best_supported_filter = (device_capabilities.RasterCaps & D3DPRASTERCAPS_ANISOTROPY ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR);  | 
        ||
| 253 | behaviour_flags = (device_capabilities.VertexProcessingCaps != 0 ? D3DCREATE_HARDWARE_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING);  | 
        ||
| 254 | |||
| 5 | pmbaty | 255 |    // see if simple (non-maskable) full-scene antialiasing is supported and in how many quality flavors | 
        
| 256 | if (SUCCEEDED (d3d->CheckDeviceMultiSampleType (D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, false, D3DMULTISAMPLE_NONMASKABLE, &multisample_quality_count)))  | 
        ||
| 257 | is_fsaa_supported = true; // remember FSAA is supported  | 
        ||
| 1 | pmbaty | 258 | |
| 259 | memset (&d3dpp, 0, sizeof (d3dpp)); // clear out the struct for use  | 
        ||
| 260 | d3dpp.Windowed = true; // always windowed (because we can't display dialog boxes in fullscreen mode)  | 
        ||
| 261 | d3dpp.BackBufferCount = 1;  | 
        ||
| 262 | d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // discard old frames  | 
        ||
| 263 | d3dpp.hDeviceWindow = hMainWnd; // set the window to be used by Direct3D  | 
        ||
| 264 | d3dpp.EnableAutoDepthStencil = true; // enable Z-buffer and stencil buffer  | 
        ||
| 265 | d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; // D3DFMT_D15S1 15 bits should be enough to store each pixel's Z depth  | 
        ||
| 5 | pmbaty | 266 | if (is_fsaa_supported)  | 
        
| 267 |    { | 
        ||
| 268 | d3dpp.MultiSampleType = D3DMULTISAMPLE_NONMASKABLE; // use multisampling (full scene antialiasing) if supported  | 
        ||
| 269 | d3dpp.MultiSampleQuality = multisample_quality_count - 1; // use the best available multisample quality  | 
        ||
| 270 |    } | 
        ||
| 271 |    else | 
        ||
| 272 |    { | 
        ||
| 273 | d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; // do not use multisampling (full scene antialiasing)  | 
        ||
| 274 | d3dpp.MultiSampleQuality = 0;  | 
        ||
| 275 |    } | 
        ||
| 1 | pmbaty | 276 | |
| 6 | pmbaty | 277 |    // get main window's current rectangle and full screen size | 
        
| 278 | GetWindowRect (hMainWnd, &rect);  | 
        ||
| 279 | |||
| 280 |    // create a device class using this information and the info from the d3dpp stuct. Resize the window to the max displayable | 
        ||
| 281 |    // size before creating the DirectX device, so as to guarantee the viewport will never be upscaled in case of window resize. | 
        ||
| 282 | MoveWindow (hMainWnd, rect.left, rect.top, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), false);  | 
        ||
| 2 | pmbaty | 283 | if (FAILED (ret = d3d->CreateDevice (D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hMainWnd, behaviour_flags, &d3dpp, &d3ddev)))  | 
        
| 1 | pmbaty | 284 |    { | 
        
| 285 | MessageBox (NULL, LOCALIZE (L"Error_CouldNotCreateD3DDevCreateDeviceFailed"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK);  | 
        ||
| 2 | pmbaty | 286 | |
| 287 |       // on error, write a log file on the user's desktop | 
        ||
| 288 | errorfile_path[0] = 0;  | 
        ||
| 289 | SHGetSpecialFolderPath (NULL, errorfile_path, CSIDL_DESKTOP, true);  | 
        ||
| 290 | wcscat_s (errorfile_path, WCHAR_SIZEOF (errorfile_path), L"\\Chess Giants error.log");  | 
        ||
| 291 | _wfopen_s (&fp, errorfile_path, L"w, ccs=UNICODE");  | 
        ||
| 292 | if (fp != NULL)  | 
        ||
| 293 |       { | 
        ||
| 294 | fwprintf (fp, L"device_capabilities.DeviceType = %d\n", device_capabilities.DeviceType);  | 
        ||
| 295 | fwprintf (fp, L"device_capabilities.AdapterOrdinal = %ul\n", device_capabilities.AdapterOrdinal);  | 
        ||
| 296 | fwprintf (fp, L"device_capabilities.Caps = %ul\n", device_capabilities.Caps);  | 
        ||
| 297 | fwprintf (fp, L"device_capabilities.Caps2 = %ul\n", device_capabilities.Caps2);  | 
        ||
| 298 | fwprintf (fp, L"device_capabilities.Caps3 = %ul\n", device_capabilities.Caps3);  | 
        ||
| 299 | fwprintf (fp, L"device_capabilities.PresentationIntervals = %ul\n", device_capabilities.PresentationIntervals);  | 
        ||
| 300 | fwprintf (fp, L"device_capabilities.CursorCaps = %ul\n", device_capabilities.CursorCaps);  | 
        ||
| 301 | fwprintf (fp, L"device_capabilities.DevCaps = %ul\n", device_capabilities.DevCaps);  | 
        ||
| 302 | fwprintf (fp, L"device_capabilities.PrimitiveMiscCaps = %ul\n", device_capabilities.PrimitiveMiscCaps);  | 
        ||
| 303 | fwprintf (fp, L"device_capabilities.RasterCaps = %ul\n", device_capabilities.RasterCaps);  | 
        ||
| 304 | fwprintf (fp, L"device_capabilities.ZCmpCaps = %ul\n", device_capabilities.ZCmpCaps);  | 
        ||
| 305 | fwprintf (fp, L"device_capabilities.SrcBlendCaps = %ul\n", device_capabilities.SrcBlendCaps);  | 
        ||
| 306 | fwprintf (fp, L"device_capabilities.DestBlendCaps = %ul\n", device_capabilities.DestBlendCaps);  | 
        ||
| 307 | fwprintf (fp, L"device_capabilities.AlphaCmpCaps = %ul\n", device_capabilities.AlphaCmpCaps);  | 
        ||
| 308 | fwprintf (fp, L"device_capabilities.ShadeCaps = %ul\n", device_capabilities.ShadeCaps);  | 
        ||
| 309 | fwprintf (fp, L"device_capabilities.TextureCaps = %ul\n", device_capabilities.TextureCaps);  | 
        ||
| 310 | fwprintf (fp, L"device_capabilities.TextureFilterCaps = %ul\n", device_capabilities.TextureFilterCaps);  | 
        ||
| 311 | fwprintf (fp, L"device_capabilities.CubeTextureFilterCaps = %ul\n", device_capabilities.CubeTextureFilterCaps);  | 
        ||
| 312 | fwprintf (fp, L"device_capabilities.VolumeTextureFilterCaps = %ul\n", device_capabilities.VolumeTextureFilterCaps);  | 
        ||
| 313 | fwprintf (fp, L"device_capabilities.TextureAddressCaps = %ul\n", device_capabilities.TextureAddressCaps);  | 
        ||
| 314 | fwprintf (fp, L"device_capabilities.VolumeTextureAddressCaps = %ul\n", device_capabilities.VolumeTextureAddressCaps);  | 
        ||
| 315 | fwprintf (fp, L"device_capabilities.LineCaps = %ul\n", device_capabilities.LineCaps);  | 
        ||
| 316 | fwprintf (fp, L"device_capabilities.MaxTextureWidth = %ul\n", device_capabilities.MaxTextureWidth);  | 
        ||
| 317 | fwprintf (fp, L"device_capabilities.MaxTextureHeight = %ul\n", device_capabilities.MaxTextureHeight);  | 
        ||
| 318 | fwprintf (fp, L"device_capabilities.MaxVolumeExtent = %ul\n", device_capabilities.MaxVolumeExtent);  | 
        ||
| 319 | fwprintf (fp, L"device_capabilities.MaxTextureRepeat = %ul\n", device_capabilities.MaxTextureRepeat);  | 
        ||
| 320 | fwprintf (fp, L"device_capabilities.MaxTextureAspectRatio = %ul\n", device_capabilities.MaxTextureAspectRatio);  | 
        ||
| 321 | fwprintf (fp, L"device_capabilities.MaxAnisotropy = %ul\n", device_capabilities.MaxAnisotropy);  | 
        ||
| 322 | fwprintf (fp, L"device_capabilities.MaxVertexW = %f\n", device_capabilities.MaxVertexW);  | 
        ||
| 323 | fwprintf (fp, L"device_capabilities.GuardBandLeft = %f\n", device_capabilities.GuardBandLeft);  | 
        ||
| 324 | fwprintf (fp, L"device_capabilities.GuardBandTop = %f\n", device_capabilities.GuardBandTop);  | 
        ||
| 325 | fwprintf (fp, L"device_capabilities.GuardBandRight = %f\n", device_capabilities.GuardBandRight);  | 
        ||
| 326 | fwprintf (fp, L"device_capabilities.GuardBandBottom = %f\n", device_capabilities.GuardBandBottom);  | 
        ||
| 327 | fwprintf (fp, L"device_capabilities.ExtentsAdjust = %f\n", device_capabilities.ExtentsAdjust);  | 
        ||
| 328 | fwprintf (fp, L"device_capabilities.StencilCaps = %ul\n", device_capabilities.StencilCaps);  | 
        ||
| 329 | fwprintf (fp, L"device_capabilities.FVFCaps = %ul\n", device_capabilities.FVFCaps);  | 
        ||
| 330 | fwprintf (fp, L"device_capabilities.TextureOpCaps = %ul\n", device_capabilities.TextureOpCaps);  | 
        ||
| 331 | fwprintf (fp, L"device_capabilities.MaxTextureBlendStages = %ul\n", device_capabilities.MaxTextureBlendStages);  | 
        ||
| 332 | fwprintf (fp, L"device_capabilities.MaxSimultaneousTextures = %ul\n", device_capabilities.MaxSimultaneousTextures);  | 
        ||
| 333 | fwprintf (fp, L"device_capabilities.VertexProcessingCaps = %ul\n", device_capabilities.VertexProcessingCaps);  | 
        ||
| 334 | fwprintf (fp, L"device_capabilities.MaxActiveLights = %ul\n", device_capabilities.MaxActiveLights);  | 
        ||
| 335 | fwprintf (fp, L"device_capabilities.MaxUserClipPlanes = %ul\n", device_capabilities.MaxUserClipPlanes);  | 
        ||
| 336 | fwprintf (fp, L"device_capabilities.MaxVertexBlendMatrices = %ul\n", device_capabilities.MaxVertexBlendMatrices);  | 
        ||
| 337 | fwprintf (fp, L"device_capabilities.MaxVertexBlendMatrixIndex = %ul\n", device_capabilities.MaxVertexBlendMatrixIndex);  | 
        ||
| 338 | fwprintf (fp, L"device_capabilities.MaxPointSize = %f\n", device_capabilities.MaxPointSize);  | 
        ||
| 339 | fwprintf (fp, L"device_capabilities.MaxPrimitiveCount = %ul\n", device_capabilities.MaxPrimitiveCount);  | 
        ||
| 340 | fwprintf (fp, L"device_capabilities.MaxVertexIndex = %ul\n", device_capabilities.MaxVertexIndex);  | 
        ||
| 341 | fwprintf (fp, L"device_capabilities.MaxStreams = %ul\n", device_capabilities.MaxStreams);  | 
        ||
| 342 | fwprintf (fp, L"device_capabilities.MaxStreamStride = %ul\n", device_capabilities.MaxStreamStride);  | 
        ||
| 343 | fwprintf (fp, L"device_capabilities.VertexShaderVersion = %ul\n", device_capabilities.VertexShaderVersion);  | 
        ||
| 344 | fwprintf (fp, L"device_capabilities.MaxVertexShaderConst = %ul\n", device_capabilities.MaxVertexShaderConst);  | 
        ||
| 345 | fwprintf (fp, L"device_capabilities.PixelShaderVersion = %ul\n", device_capabilities.PixelShaderVersion);  | 
        ||
| 346 | fwprintf (fp, L"device_capabilities.PixelShader1xMaxValue = %f\n", device_capabilities.PixelShader1xMaxValue);  | 
        ||
| 347 | fwprintf (fp, L"device_capabilities.DevCaps2 = %ul\n", device_capabilities.DevCaps2);  | 
        ||
| 348 | fwprintf (fp, L"device_capabilities.MaxNpatchTessellationLevel = %f\n", device_capabilities.MaxNpatchTessellationLevel);  | 
        ||
| 349 | fwprintf (fp, L"device_capabilities.Reserved5 = %ul\n", device_capabilities.Reserved5);  | 
        ||
| 350 | fwprintf (fp, L"device_capabilities.MasterAdapterOrdinal = %ul\n", device_capabilities.MasterAdapterOrdinal);  | 
        ||
| 351 | fwprintf (fp, L"device_capabilities.AdapterOrdinalInGroup = %ul\n", device_capabilities.AdapterOrdinalInGroup);  | 
        ||
| 352 | fwprintf (fp, L"device_capabilities.NumberOfAdaptersInGroup = %ul\n", device_capabilities.NumberOfAdaptersInGroup);  | 
        ||
| 353 | fwprintf (fp, L"device_capabilities.DeclTypes = %ul\n", device_capabilities.DeclTypes);  | 
        ||
| 354 | fwprintf (fp, L"device_capabilities.NumSimultaneousRTs = %ul\n", device_capabilities.NumSimultaneousRTs);  | 
        ||
| 355 | fwprintf (fp, L"device_capabilities.StretchRectFilterCaps = %ul\n", device_capabilities.StretchRectFilterCaps);  | 
        ||
| 356 | fwprintf (fp, L"device_capabilities.VS20Caps.Caps = %ul\n", device_capabilities.VS20Caps.Caps);  | 
        ||
| 357 | fwprintf (fp, L"device_capabilities.VS20Caps.DynamicFlowControlDepth = %d\n", device_capabilities.VS20Caps.DynamicFlowControlDepth);  | 
        ||
| 358 | fwprintf (fp, L"device_capabilities.VS20Caps.NumTemps = %d\n", device_capabilities.VS20Caps.NumTemps);  | 
        ||
| 359 | fwprintf (fp, L"device_capabilities.VS20Caps.StaticFlowControlDepth = %d\n", device_capabilities.VS20Caps.StaticFlowControlDepth);  | 
        ||
| 360 | fwprintf (fp, L"device_capabilities.PS20Caps.Caps = %ul\n", device_capabilities.PS20Caps.Caps);  | 
        ||
| 361 | fwprintf (fp, L"device_capabilities.PS20Caps.DynamicFlowControlDepth = %d\n", device_capabilities.PS20Caps.DynamicFlowControlDepth);  | 
        ||
| 362 | fwprintf (fp, L"device_capabilities.PS20Caps.NumTemps = %d\n", device_capabilities.PS20Caps.NumTemps);  | 
        ||
| 363 | fwprintf (fp, L"device_capabilities.PS20Caps.StaticFlowControlDepth = %d\n", device_capabilities.PS20Caps.StaticFlowControlDepth);  | 
        ||
| 364 | fwprintf (fp, L"device_capabilities.PS20Caps.NumInstructionSlots = %d\n", device_capabilities.PS20Caps.NumInstructionSlots);  | 
        ||
| 365 | fwprintf (fp, L"device_capabilities.VertexTextureFilterCaps = %ul\n", device_capabilities.VertexTextureFilterCaps);  | 
        ||
| 366 | fwprintf (fp, L"device_capabilities.MaxVShaderInstructionsExecuted = %ul\n", device_capabilities.MaxVShaderInstructionsExecuted);  | 
        ||
| 367 | fwprintf (fp, L"device_capabilities.MaxPShaderInstructionsExecuted = %ul\n", device_capabilities.MaxPShaderInstructionsExecuted);  | 
        ||
| 368 | fwprintf (fp, L"device_capabilities.MaxVertexShader30InstructionSlots = %ul\n", device_capabilities.MaxVertexShader30InstructionSlots);  | 
        ||
| 369 | fwprintf (fp, L"device_capabilities.MaxPixelShader30InstructionSlots = %ul\n", device_capabilities.MaxPixelShader30InstructionSlots);  | 
        ||
| 370 | fwprintf (fp, L"========\n");  | 
        ||
| 371 | fwprintf (fp, L"(guessed) behaviour_flags = %ul\n", behaviour_flags);  | 
        ||
| 372 | fwprintf (fp, L"========\n");  | 
        ||
| 5 | pmbaty | 373 | fwprintf (fp, L"d3dpp.MultiSampleType = %d\n", d3dpp.MultiSampleType);  | 
        
| 374 | fwprintf (fp, L"d3dpp.MultiSampleQuality = %d\n", d3dpp.MultiSampleQuality);  | 
        ||
| 375 | fwprintf (fp, L"========\n");  | 
        ||
| 2 | pmbaty | 376 | fwprintf (fp, L"d3d->CreateDevice() returned %d\n", (int) ret);  | 
        
| 377 | fclose (fp);  | 
        ||
| 378 | |||
| 379 | MessageBox (NULL, LOCALIZE (L"Error_GameCouldNotStartPleaseSendLogToAuthor"), LOCALIZE (L"Information"), MB_ICONINFORMATION | MB_OK);  | 
        ||
| 380 |       } | 
        ||
| 381 |       else | 
        ||
| 382 | MessageBox (NULL, LOCALIZE (L"Error_CouldNotWriteToLogFile"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK);  | 
        ||
| 383 | |||
| 11 | pmbaty | 384 | terminate_everything = true; // this is a fatal error  | 
        
| 1 | pmbaty | 385 | return (false);  | 
        
| 386 |    } | 
        ||
| 387 | |||
| 6 | pmbaty | 388 |    // save the viewport's width and height | 
        
| 389 | GetClientRect (hMainWnd, &viewport_rect);  | 
        ||
| 390 | initial_width = viewport_rect.right;  | 
        ||
| 391 | initial_height = viewport_rect.bottom;  | 
        ||
| 1 | pmbaty | 392 | |
| 6 | pmbaty | 393 |    // now resize the window to its original size | 
        
| 394 | MoveWindow (hMainWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, false);  | 
        ||
| 395 | |||
| 1 | pmbaty | 396 |    // set the texture parameters | 
        
| 397 | d3ddev->SetSamplerState (0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); // wrap textures around their edges  | 
        ||
| 398 | d3ddev->SetSamplerState (0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);  | 
        ||
| 399 | d3ddev->SetTextureStageState (0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); // and modulate their alpha with the material's alpha  | 
        ||
| 400 | d3ddev->SetTextureStageState (0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);  | 
        ||
| 401 | d3ddev->SetTextureStageState (0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);  | 
        ||
| 402 | |||
| 403 |    // enable the Z buffer | 
        ||
| 404 | d3ddev->SetRenderState (D3DRS_ZENABLE, true);  | 
        ||
| 405 | |||
| 406 |    // disable the stencil buffer | 
        ||
| 407 | d3ddev->SetRenderState (D3DRS_STENCILENABLE, false);  | 
        ||
| 408 | |||
| 409 |    // normalize the face normals (if we don't, scaling will cause problems with lighting computations) | 
        ||
| 410 | d3ddev->SetRenderState (D3DRS_NORMALIZENORMALS, true);  | 
        ||
| 411 | |||
| 412 |    // turn on alpha blending | 
        ||
| 413 | d3ddev->SetRenderState (D3DRS_ALPHABLENDENABLE, true);  | 
        ||
| 414 | d3ddev->SetRenderState (D3DRS_BLENDOP, D3DBLENDOP_ADD);  | 
        ||
| 415 | d3ddev->SetRenderState (D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);  | 
        ||
| 416 | d3ddev->SetRenderState (D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);  | 
        ||
| 417 | |||
| 418 |    // use all of the materials' light reflection properties | 
        ||
| 419 | d3ddev->SetRenderState (D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);  | 
        ||
| 420 | d3ddev->SetRenderState (D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);  | 
        ||
| 421 | d3ddev->SetRenderState (D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL);  | 
        ||
| 422 | d3ddev->SetRenderState (D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL);  | 
        ||
| 423 | d3ddev->SetRenderState (D3DRS_COLORVERTEX, false);  | 
        ||
| 424 | |||
| 425 |    // enable 3D lighting | 
        ||
| 426 | d3ddev->SetRenderState (D3DRS_LIGHTING, true);  | 
        ||
| 427 | |||
| 116 | pmbaty | 428 |    // load the splash screen sprite and display it | 
        
| 429 | int bgsprite_index = Render_LoadSprite (splashscreen_pathname);  | 
        ||
| 430 | d3ddev->Clear (0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_XRGB (0, 0, 0), 1.0f, 0);  | 
        ||
| 431 | d3ddev->BeginScene (); // begins the 3D scene  | 
        ||
| 432 | Render_DrawSprite (&sprites[bgsprite_index], 0.0f, 0.0f, 100.0f, 100.0f, 0xFF); // draw the background sprite  | 
        ||
| 433 | d3ddev->EndScene (); // ends the 3D scene  | 
        ||
| 434 | d3ddev->Present (NULL, NULL, NULL, NULL); // displays the created frame on the screen  | 
        ||
| 435 | |||
| 1 | pmbaty | 436 |    // open and parse the materials file and build the materials list | 
        
| 437 | materials = NULL;  | 
        ||
| 438 | material_count = 0;  | 
        ||
| 439 | _wfopen_s (&fp, L"materials.cfg", L"r, ccs=UNICODE");  | 
        ||
| 440 | if (fp != NULL)  | 
        ||
| 441 |    { | 
        ||
| 442 |       // read line per line... | 
        ||
| 443 | while (fgetws (line_buffer, WCHAR_SIZEOF (line_buffer), fp) != NULL)  | 
        ||
| 444 |       { | 
        ||
| 445 |          // can we read a complete material line ? | 
        ||
| 446 | if (swscanf_s (line_buffer, L"\"%[^\"]\" %f %f %f %f %f %f", material.name, WCHAR_SIZEOF (material.name), &material.ambient, &material.diffuse, &material.emissive, &material.specular, &material.shininess, &material.transparency) == 7)  | 
        ||
| 447 |          { | 
        ||
| 448 | materials = (material_t *) SAFE_realloc (materials, material_count, material_count + 1, sizeof (material_t), false);  | 
        ||
| 449 | memcpy (&materials[material_count], &material, sizeof (material_t));  | 
        ||
| 450 | material_count++; // if so, append this new material to the materials array  | 
        ||
| 451 |          } | 
        ||
| 452 |       } | 
        ||
| 453 | fclose (fp); // finished, close the file  | 
        ||
| 454 |    } | 
        ||
| 455 | materials = (material_t *) SAFE_realloc (materials, material_count, material_count + 1, sizeof (material_t), false);  | 
        ||
| 456 | wcscpy_s (materials[material_count].name, WCHAR_SIZEOF (materials[material_count].name), default_materialname);  | 
        ||
| 457 | materials[material_count].ambient = 1.0f;  | 
        ||
| 458 | materials[material_count].diffuse = 1.0f;  | 
        ||
| 459 | materials[material_count].emissive = 0.0f;  | 
        ||
| 460 | materials[material_count].specular = 0.0f;  | 
        ||
| 461 | materials[material_count].shininess = 0.0f;  | 
        ||
| 462 | materials[material_count].transparency = 1.0f;  | 
        ||
| 463 | material_count++; // append a default material at the end of the array and we're all set  | 
        ||
| 464 | |||
| 465 | return (true); // finished  | 
        ||
| 466 | } | 
        ||
| 467 | |||
| 468 | |||
| 469 | void Render_Shutdown (void)  | 
        ||
| 470 | { | 
        ||
| 471 |    // this function shuts down the Direct3D interfaces and releases the Direct3D COM objects | 
        ||
| 472 | |||
| 473 | int array_index;  | 
        ||
| 474 | |||
| 475 |    // close and release font data | 
        ||
| 476 | SAFE_free ((void **) &fonts);  | 
        ||
| 477 | font_count = 0;  | 
        ||
| 478 | |||
| 479 |    // close and release sprite data | 
        ||
| 480 | SAFE_free ((void **) &sprites);  | 
        ||
| 481 | sprite_count = 0;  | 
        ||
| 482 | |||
| 483 |    // close and release meshes data | 
        ||
| 484 | if (meshes != NULL)  | 
        ||
| 485 |    { | 
        ||
| 486 | for (array_index = 0; array_index < mesh_count; array_index++)  | 
        ||
| 487 |       { | 
        ||
| 488 | if (meshes[array_index].d3dindices != NULL)  | 
        ||
| 489 | meshes[array_index].d3dindices->Release ();  | 
        ||
| 490 | meshes[array_index].d3dindices = NULL;  | 
        ||
| 491 | |||
| 492 | if (meshes[array_index].d3dvertices != NULL)  | 
        ||
| 493 | meshes[array_index].d3dvertices->Release ();  | 
        ||
| 494 | meshes[array_index].d3dvertices = NULL;  | 
        ||
| 495 |       } | 
        ||
| 496 |    } | 
        ||
| 497 | meshes = NULL;  | 
        ||
| 498 | mesh_count = 0;  | 
        ||
| 499 | |||
| 500 |    // close and release texture data | 
        ||
| 501 | if (textures != NULL)  | 
        ||
| 502 |    { | 
        ||
| 503 | for (array_index = 0; array_index < texture_count; array_index++)  | 
        ||
| 504 | if (textures[array_index].texture != NULL)  | 
        ||
| 505 | textures[array_index].texture->Release ();  | 
        ||
| 506 | SAFE_free ((void **) &textures);  | 
        ||
| 507 |    } | 
        ||
| 508 | texture_count = 0;  | 
        ||
| 509 | |||
| 510 |    // close and release materials data | 
        ||
| 511 | SAFE_free ((void **) &materials);  | 
        ||
| 512 | material_count = 0;  | 
        ||
| 513 | |||
| 514 |    // close and release the 3D device | 
        ||
| 515 | if (d3ddev != NULL)  | 
        ||
| 516 | d3ddev->Release ();  | 
        ||
| 517 | d3ddev = NULL;  | 
        ||
| 518 | |||
| 519 |    // close and release Direct3D | 
        ||
| 520 | if (d3d != NULL)  | 
        ||
| 521 | d3d->Release ();  | 
        ||
| 522 | d3d = NULL;  | 
        ||
| 523 | |||
| 524 | return; // finished  | 
        ||
| 525 | } | 
        ||
| 526 | |||
| 527 | |||
| 528 | void Render_RenderFrame (scene_t *scene)  | 
        ||
| 529 | { | 
        ||
| 530 |    // this is the function used to render a single frame | 
        ||
| 531 | |||
| 532 | static int framerate_value = 0;  | 
        ||
| 533 | static int framerate_count = 0;  | 
        ||
| 534 | static float framerate_time = 0;  | 
        ||
| 535 | |||
| 536 |    D3DXMATRIX scaling_matrix; | 
        ||
| 537 |    D3DXMATRIX translation_matrix; | 
        ||
| 538 | D3DXMATRIX view_matrix; // the view transform matrix  | 
        ||
| 539 | D3DXMATRIX projection_matrix; // the projection transform matrix  | 
        ||
| 540 |    D3DLIGHT9 dxlight; | 
        ||
| 541 |    RECT rect; | 
        ||
| 542 | float angle;  | 
        ||
| 543 | float sin_pitch;  | 
        ||
| 544 | float sin_yaw;  | 
        ||
| 545 | float cos_pitch;  | 
        ||
| 546 | float cos_yaw;  | 
        ||
| 547 | int light_index;  | 
        ||
| 548 | int object_index;  | 
        ||
| 549 | int cchistory_index;  | 
        ||
| 550 | int cchistory_index2;  | 
        ||
| 124 | pmbaty | 551 | float combinedwidth_percent;  | 
        
| 552 | float combinedheight_percent;  | 
        ||
| 1 | pmbaty | 553 | light_t *light;  | 
        
| 554 | ccreply_t *ccreply;  | 
        ||
| 555 | sceneobject_t *sceneobject;  | 
        ||
| 556 | reflectedobject_t *reflectedobjects; // mallocated  | 
        ||
| 557 | int reflectedobject_count;  | 
        ||
| 558 | reflectedobject_t *otherobjects; // mallocated  | 
        ||
| 559 | int otherobject_count;  | 
        ||
| 560 | |||
| 11 | pmbaty | 561 | if (terminate_everything)  | 
        
| 562 | return; // consistency check  | 
        ||
| 563 | |||
| 1 | pmbaty | 564 |    // get the device view port and save the actual width and height | 
        
| 565 | GetClientRect (hMainWnd, &rect);  | 
        ||
| 566 | current_width = (float) rect.right; // they may differ from window width and window height  | 
        ||
| 567 | current_height = (float) rect.bottom; // because of title bars, menus, borders, etc.  | 
        ||
| 568 | |||
| 569 |    // clear the back buffer, the Z buffer and the stencil buffer | 
        ||
| 570 | d3ddev->Clear (0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_XRGB (0, 0, 0), 1.0f, 0);  | 
        ||
| 571 | d3ddev->BeginScene (); // begins the 3D scene  | 
        ||
| 572 | |||
| 573 |    //////////////////////////////////////// | 
        ||
| 574 |    // Setup scene lights | 
        ||
| 575 | |||
| 576 |    // There are three types of light : ambient, diffuse and specular. | 
        ||
| 577 |    // Diffuse lights can be of type directional (sun), point (bulb) or spot (flashlight). | 
        ||
| 578 | |||
| 579 |    // The attenuation formula for point lights is : | 
        ||
| 580 |    // Atten = 1 / (att0 + (att1 * d) + (att2 * d²)) | 
        ||
| 581 | |||
| 582 |    // In spot lights, Phi is the outer cone angle. Theta is the inner cone angle. | 
        ||
| 583 | |||
| 584 |    // set the default lighting color | 
        ||
| 585 | ambient_light = RGBACOLOR_TO_ARGBCOLOR (RGBACOLOR_FULLALPHA (theme->illum.ambient_light));  | 
        ||
| 586 | d3ddev->SetRenderState (D3DRS_AMBIENT, ambient_light);  | 
        ||
| 587 | |||
| 588 |    // for each light... | 
        ||
| 589 | for (light_index = 0; light_index < theme->illum.light_count; light_index++)  | 
        ||
| 590 |    { | 
        ||
| 591 | light = &theme->illum.lights[light_index]; // quick access to light  | 
        ||
| 592 | |||
| 593 | memset (&dxlight, 0, sizeof (dxlight)); // clear out the dxlight struct for use  | 
        ||
| 594 | |||
| 595 |       // set its type | 
        ||
| 596 | if (light->type == LIGHT_DIRECTIONAL)  | 
        ||
| 597 | dxlight.Type = D3DLIGHT_DIRECTIONAL; // directional light (e.g, sun)  | 
        ||
| 598 | else if (light->type == LIGHT_POINT)  | 
        ||
| 599 | dxlight.Type = D3DLIGHT_POINT; // point light (e.g, light bulb)  | 
        ||
| 600 | else if (light->type == LIGHT_SPOT)  | 
        ||
| 601 | dxlight.Type = D3DLIGHT_SPOT; // spot light (e.g, flash light)  | 
        ||
| 602 |       else | 
        ||
| 603 |       { | 
        ||
| 604 | d3ddev->LightEnable (light_index, false); // unknown light ; turn off light #index  | 
        ||
| 605 | continue; // and proceed to the next one  | 
        ||
| 606 |       } | 
        ||
| 607 | |||
| 608 |       // set its parameters | 
        ||
| 609 | dxlight.Diffuse = D3DXCOLOR (RGBACOLOR_TO_ARGBCOLOR (RGBACOLOR_FULLALPHA (light->color)));  | 
        ||
| 610 | dxlight.Specular = D3DXCOLOR (0xffffffff);  | 
        ||
| 611 | dxlight.Position.x = light->pos_x;  | 
        ||
| 612 | dxlight.Position.y = light->pos_y;  | 
        ||
| 613 | dxlight.Position.z = light->pos_z;  | 
        ||
| 614 | dxlight.Direction.x = light->direction_x;  | 
        ||
| 615 | dxlight.Direction.y = light->direction_y;  | 
        ||
| 616 | dxlight.Direction.z = light->direction_z;  | 
        ||
| 617 | dxlight.Range = light->range; // light won't be computed after this distance  | 
        ||
| 618 | dxlight.Attenuation0 = light->attenuation_constant; // constant attenuation, see formula  | 
        ||
| 619 | dxlight.Attenuation1 = light->attenuation_proportional; // proportional attenuation, see formula  | 
        ||
| 620 | dxlight.Attenuation2 = light->attenuation_square; // square attenuation, see formula  | 
        ||
| 621 | dxlight.Phi = light->cone_outer * TO_RADIANS; // outer spot cone  | 
        ||
| 622 | dxlight.Theta = light->cone_inner * TO_RADIANS; // inner spot cone  | 
        ||
| 623 | |||
| 624 | d3ddev->SetLight (light_index, &dxlight); // send the light struct properties to light #index  | 
        ||
| 625 | d3ddev->LightEnable (light_index, true); // turn on light #index  | 
        ||
| 626 |    } | 
        ||
| 627 | |||
| 628 |    //////////////////////////////// | 
        ||
| 629 |    // View transform | 
        ||
| 630 | |||
| 131 | pmbaty | 631 |    // update the point looked at | 
        
| 632 | scene_lookatpoint.x = lookatpoint_x;  | 
        ||
| 633 | scene_lookatpoint.y = lookatpoint_y;  | 
        ||
| 634 | |||
| 1 | pmbaty | 635 |    // compute the sine and cosine of the pitch component | 
        
| 636 | angle = current_pitch * TO_RADIANS;  | 
        ||
| 637 | sin_pitch = sinf (angle);  | 
        ||
| 638 | cos_pitch = cosf (angle);  | 
        ||
| 639 | |||
| 640 |    // compute the sine and cosine of the yaw component | 
        ||
| 641 | angle = current_yaw * TO_RADIANS;  | 
        ||
| 642 | sin_yaw = sinf (angle);  | 
        ||
| 643 | cos_yaw = cosf (angle);  | 
        ||
| 644 | |||
| 645 |    // build the camera position | 
        ||
| 131 | pmbaty | 646 | camera_position.x = scene_lookatpoint.x + (float) -(cos_pitch * cos_yaw) * current_distance;  | 
        
| 647 | camera_position.y = scene_lookatpoint.y + (float) -(cos_pitch * sin_yaw) * current_distance;  | 
        ||
| 1 | pmbaty | 648 | camera_position.z = (float) sin_pitch * current_distance;  | 
        
| 649 | |||
| 650 |    // set up a view matrix | 
        ||
| 651 | D3DXMatrixLookAtLH (&view_matrix,  | 
        ||
| 652 | (D3DXVECTOR3 *) &camera_position, // camera position  | 
        ||
| 131 | pmbaty | 653 | (D3DXVECTOR3 *) &scene_lookatpoint, // look-at position  | 
        
| 1 | pmbaty | 654 | (D3DXVECTOR3 *) &upwards_direction); // up direction  | 
        
| 655 | |||
| 656 |    // tell Direct3D about our matrix | 
        ||
| 657 | d3ddev->SetTransform (D3DTS_VIEW, &view_matrix);  | 
        ||
| 658 | |||
| 659 |    ///////////////////////////////////// | 
        ||
| 660 |    // Projection transform | 
        ||
| 661 | |||
| 662 |    // set up a projection matrix | 
        ||
| 663 | D3DXMatrixPerspectiveFovLH (&projection_matrix,  | 
        ||
| 664 | fov_value * TO_RADIANS, // field of view width  | 
        ||
| 665 | current_width / current_height, // aspect ratio  | 
        ||
| 666 | viewdist_near, viewdist_far); // view plane distances  | 
        ||
| 667 | |||
| 668 |    // tell Direct3D about our matrix | 
        ||
| 669 | d3ddev->SetTransform (D3DTS_PROJECTION, &projection_matrix);  | 
        ||
| 670 | |||
| 671 |    ///////////////////////////////////// | 
        ||
| 672 |    // End of the transforms | 
        ||
| 673 | |||
| 674 |    // if we want it, enable specular lighting | 
        ||
| 675 | d3ddev->SetRenderState (D3DRS_SPECULARENABLE, options.want_specularlighting);  | 
        ||
| 676 | |||
| 677 |    // turn on texture filtering if needed | 
        ||
| 678 | if (options.want_filtering)  | 
        ||
| 679 |    { | 
        ||
| 680 | d3ddev->SetSamplerState (0, D3DSAMP_MINFILTER, best_supported_filter);  | 
        ||
| 681 | d3ddev->SetSamplerState (0, D3DSAMP_MAGFILTER, best_supported_filter);  | 
        ||
| 682 | d3ddev->SetSamplerState (0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);  | 
        ||
| 683 | |||
| 684 |       // turn on fullscene antialiasing only if capable | 
        ||
| 5 | pmbaty | 685 | d3ddev->SetRenderState (D3DRS_MULTISAMPLEANTIALIAS, is_fsaa_supported);  | 
        
| 1 | pmbaty | 686 |    } | 
        
| 687 |    else | 
        ||
| 688 |    { | 
        ||
| 689 | d3ddev->SetSamplerState (0, D3DSAMP_MINFILTER, D3DTEXF_NONE);  | 
        ||
| 690 | d3ddev->SetSamplerState (0, D3DSAMP_MAGFILTER, D3DTEXF_NONE);  | 
        ||
| 691 | d3ddev->SetSamplerState (0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);  | 
        ||
| 692 | |||
| 693 |       // turn off fullscene antialiasing | 
        ||
| 694 | d3ddev->SetRenderState (D3DRS_MULTISAMPLEANTIALIAS, false);  | 
        ||
| 695 |    } | 
        ||
| 696 | |||
| 697 |    ///////////////////////////////////////////////////////////// | 
        ||
| 698 |    // draw the background elements. No need for a Z buffer here. | 
        ||
| 699 | |||
| 700 | d3ddev->SetRenderState (D3DRS_ZENABLE, false); // disable depth testing  | 
        ||
| 701 | |||
| 702 |    // draw the background sprite, if any | 
        ||
| 703 | if (scene->background_spriteindex >= 0)  | 
        ||
| 704 | Render_DrawSprite (&sprites[scene->background_spriteindex], 0.0f, 0.0f, 100.0f, 100.0f, 0xFF);  | 
        ||
| 705 | |||
| 706 |    // draw the table border | 
        ||
| 707 | Render_DrawSceneObject (&scene->objects[0]);  | 
        ||
| 708 | Render_DrawSceneObject (&scene->objects[1]);  | 
        ||
| 709 | |||
| 710 |    // draw the table and build the stencil buffer at the same time | 
        ||
| 711 | d3ddev->SetRenderState (D3DRS_STENCILENABLE, true); // enable the stencil buffer (i.e. the "frame" for drawing table reflections)  | 
        ||
| 712 | d3ddev->SetRenderState (D3DRS_STENCILFUNC, D3DCMP_ALWAYS); // instruct how to fill it  | 
        ||
| 713 | d3ddev->SetRenderState (D3DRS_STENCILPASS, D3DSTENCILOP_INCRSAT); // instruct how to fill it  | 
        ||
| 714 | Render_DrawSceneObject (&scene->objects[2]); // draw the table squares in the stencil buffer  | 
        ||
| 715 | d3ddev->SetRenderState (D3DRS_STENCILENABLE, false); // finished drawing the stencil buffer  | 
        ||
| 716 | |||
| 717 | d3ddev->SetRenderState (D3DRS_ZENABLE, true); // re-enable depth testing  | 
        ||
| 718 | |||
| 719 |    //////////////////////////////////////////////////////////// | 
        ||
| 720 |    // draw the scene objects and their reflections on the table | 
        ||
| 721 | |||
| 722 |    // start with the reflections if we want them, and if the table does it | 
        ||
| 723 | if (options.want_reflections && (theme->reflection_alpha > 0))  | 
        ||
| 724 |    { | 
        ||
| 725 |       // build an array of reflected objects with their distances | 
        ||
| 726 | reflectedobjects = NULL;  | 
        ||
| 727 | reflectedobject_count = 0;  | 
        ||
| 728 | otherobjects = NULL;  | 
        ||
| 729 | otherobject_count = 0;  | 
        ||
| 730 | |||
| 731 |       // cycle through all parts and see which ones need to be reflected | 
        ||
| 732 | for (object_index = 3; object_index < scene->object_count; object_index++)  | 
        ||
| 733 |       { | 
        ||
| 734 | sceneobject = &scene->objects[object_index]; // quick access to scene object  | 
        ||
| 735 | |||
| 736 |          // is this object a mesh AND it's above the ground ? | 
        ||
| 737 | if ((sceneobject->mesh_index != -1) && (sceneobject->z > 0))  | 
        ||
| 738 |          { | 
        ||
| 739 |             // yes it is. It thus needs to be reflected, so add it to the list | 
        ||
| 740 | reflectedobjects = (reflectedobject_t *) SAFE_realloc (reflectedobjects, reflectedobject_count, reflectedobject_count + 1, sizeof (reflectedobject_t), false);  | 
        ||
| 741 | reflectedobjects[reflectedobject_count].object = sceneobject; // save scene object  | 
        ||
| 742 | reflectedobjects[reflectedobject_count].distance = DistanceToCamera (sceneobject->x, sceneobject->y, sceneobject->z);  | 
        ||
| 743 | reflectedobject_count++; // we have now one object more to reflect  | 
        ||
| 744 |          } | 
        ||
| 745 |          else | 
        ||
| 746 |          { | 
        ||
| 747 |             // no it's not. It doesn't need to be reflected, so add it to the other list | 
        ||
| 748 | otherobjects = (reflectedobject_t *) SAFE_realloc (otherobjects, otherobject_count, otherobject_count + 1, sizeof (reflectedobject_t), false);  | 
        ||
| 749 | otherobjects[otherobject_count].object = sceneobject; // save scene object  | 
        ||
| 750 | otherobjects[otherobject_count].distance = 0;  | 
        ||
| 751 | otherobject_count++; // we have now one object more to reflect  | 
        ||
| 752 |          } | 
        ||
| 753 |       } | 
        ||
| 754 | |||
| 755 |       // now sort them from farthest to closest and draw them in this order | 
        ||
| 756 | qsort (reflectedobjects, reflectedobject_count, sizeof (reflectedobject_t), SortReflectedObjects);  | 
        ||
| 757 | for (object_index = 0; object_index < reflectedobject_count; object_index++)  | 
        ||
| 758 | Render_DrawSceneObjectReflection (reflectedobjects[object_index].object); // draw the reflection  | 
        ||
| 759 | for (object_index = 0; object_index < reflectedobject_count; object_index++)  | 
        ||
| 760 | Render_DrawSceneObject (reflectedobjects[object_index].object); // and draw the objects afterwards  | 
        ||
| 761 | for (object_index = 0; object_index < otherobject_count; object_index++)  | 
        ||
| 762 | Render_DrawSceneObject (otherobjects[object_index].object); // finally, draw the non-reflected objects  | 
        ||
| 763 | |||
| 764 | SAFE_free ((void **) &reflectedobjects); // and free the reflected objects array  | 
        ||
| 765 | SAFE_free ((void **) &otherobjects); // and the non-reflected objects array  | 
        ||
| 766 |    } | 
        ||
| 767 |    else | 
        ||
| 768 | for (object_index = 3; object_index < scene->object_count; object_index++)  | 
        ||
| 769 | Render_DrawSceneObject (&scene->objects[object_index]); // else if no reflections, draw the objects, the Z-buffer will sort them  | 
        ||
| 770 | |||
| 771 |    // draw the overlay texture if required | 
        ||
| 772 | if (scene->overlay_spriteindex >= 0)  | 
        ||
| 773 | Render_DrawSprite (&sprites[scene->overlay_spriteindex], 0.0f, 0.0f, 100.0f, 100.0f, 0x4F);  | 
        ||
| 774 | |||
| 775 |    /////////////// | 
        ||
| 776 |    // draw the GUI | 
        ||
| 777 | |||
| 124 | pmbaty | 778 | DRAW_BUTTON_IF_NEEDED (scene->gui.newgamebutton); // new game  | 
        
| 779 | DRAW_BUTTON_IF_NEEDED (scene->gui.opengamebutton); // open game  | 
        ||
| 780 | |||
| 1 | pmbaty | 781 |    // draw the arrows | 
        
| 140 | pmbaty | 782 | DRAW_BUTTON_IF_NEEDED (scene->gui.llarrow); // "jump to beginning" arrow  | 
        
| 783 | DRAW_BUTTON_IF_NEEDED (scene->gui.larrow); // "previous move" arrow  | 
        ||
| 784 | DRAW_BUTTON_IF_NEEDED (scene->gui.rarrow); // "next move" arrow  | 
        ||
| 785 | DRAW_BUTTON_IF_NEEDED (scene->gui.rrarrow); // "jump to end" arrow  | 
        ||
| 1 | pmbaty | 786 | DRAW_TEXT_IF_NEEDED (scene->gui.arrow_text); // arrow text  | 
        
| 787 | |||
| 788 | if (want_framerate)  | 
        ||
| 124 | pmbaty | 789 | Render_wprintf (99.0f, 1.0f, 0.0f, ALIGN_RIGHT, ALIGN_TOP, ALIGN_CENTER, arrow_fontindex, D3DCOLOR_RGBA (255, 255, 255, 255), NULL,  | 
        
| 1 | pmbaty | 790 | L"%d textures\n"  | 
        
| 791 | L"%d meshes\n"  | 
        ||
| 792 | L"%d fonts\n"  | 
        ||
| 793 | L"%d sprites\n"  | 
        ||
| 794 | L"%d fps", texture_count, mesh_count, font_count, sprite_count, framerate_value);  | 
        ||
| 795 | |||
| 796 |    // draw the other GUI buttons | 
        ||
| 797 | DRAW_BUTTON_IF_NEEDED (scene->gui.chatbutton); // chat button  | 
        ||
| 798 | DRAW_BUTTON_IF_NEEDED (scene->gui.gamesbutton); // games button  | 
        ||
| 799 | DRAW_BUTTON_IF_NEEDED (scene->gui.peoplebutton); // people button  | 
        ||
| 800 | |||
| 801 |    // does the parts pick line need to be displayed ? | 
        ||
| 802 | if (scene->gui.is_partspick_displayed)  | 
        ||
| 803 |    { | 
        ||
| 804 | #define PARTSIZE_PCT (100.0f / 13.0f) | 
        ||
| 805 | |||
| 806 | if (scene->gui.partspick_selectedpart == 'P') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 0.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);  | 
        ||
| 807 | else if (scene->gui.partspick_selectedpart == 'R') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 1.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);  | 
        ||
| 808 | else if (scene->gui.partspick_selectedpart == 'N') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 2.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);  | 
        ||
| 809 | else if (scene->gui.partspick_selectedpart == 'B') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 3.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);  | 
        ||
| 810 | else if (scene->gui.partspick_selectedpart == 'Q') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 4.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);  | 
        ||
| 811 | else if (scene->gui.partspick_selectedpart == 'K') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 5.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);  | 
        ||
| 812 | else if (scene->gui.partspick_selectedpart == ' ') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 6.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);  | 
        ||
| 813 | else if (scene->gui.partspick_selectedpart == 'k') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 7.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);  | 
        ||
| 814 | else if (scene->gui.partspick_selectedpart == 'q') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 8.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);  | 
        ||
| 815 | else if (scene->gui.partspick_selectedpart == 'b') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 9.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);  | 
        ||
| 816 | else if (scene->gui.partspick_selectedpart == 'n') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 10.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);  | 
        ||
| 817 | else if (scene->gui.partspick_selectedpart == 'r') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 11.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);  | 
        ||
| 818 | else if (scene->gui.partspick_selectedpart == 'p') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 12.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);  | 
        ||
| 819 | |||
| 820 | Render_DrawSprite (&sprites[theme->flatsprites[COLOR_WHITE][PART_PAWN]], 0.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'P') || (scene->gui.partspick_selectedpart == 'P')) ? 0xFF : 0x7F)); // white pawn  | 
        ||
| 821 | Render_DrawSprite (&sprites[theme->flatsprites[COLOR_WHITE][PART_ROOK]], 1.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'R') || (scene->gui.partspick_selectedpart == 'R')) ? 0xFF : 0x7F)); // white rook  | 
        ||
| 822 | Render_DrawSprite (&sprites[theme->flatsprites[COLOR_WHITE][PART_KNIGHT]], 2.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'N') || (scene->gui.partspick_selectedpart == 'N')) ? 0xFF : 0x7F)); // white knight  | 
        ||
| 823 | Render_DrawSprite (&sprites[theme->flatsprites[COLOR_WHITE][PART_BISHOP]], 3.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'B') || (scene->gui.partspick_selectedpart == 'B')) ? 0xFF : 0x7F)); // white bishop  | 
        ||
| 824 | Render_DrawSprite (&sprites[theme->flatsprites[COLOR_WHITE][PART_QUEEN]], 4.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'Q') || (scene->gui.partspick_selectedpart == 'Q')) ? 0xFF : 0x7F)); // white queen  | 
        ||
| 825 | Render_DrawSprite (&sprites[theme->flatsprites[COLOR_WHITE][PART_KING]], 5.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'K') || (scene->gui.partspick_selectedpart == 'K')) ? 0xFF : 0x7F)); // white king  | 
        ||
| 826 | Render_DrawSprite (&sprites[theme->lastmovesource_spriteindex], 6.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == ' ') || (scene->gui.partspick_selectedpart == ' ')) ? 0xFF : 0x7F)); // erase mark  | 
        ||
| 827 | Render_DrawSprite (&sprites[theme->flatsprites[COLOR_BLACK][PART_KING]], 7.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'k') || (scene->gui.partspick_selectedpart == 'k')) ? 0xFF : 0x7F)); // black king  | 
        ||
| 828 | Render_DrawSprite (&sprites[theme->flatsprites[COLOR_BLACK][PART_QUEEN]], 8.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'q') || (scene->gui.partspick_selectedpart == 'q')) ? 0xFF : 0x7F)); // black queen  | 
        ||
| 829 | Render_DrawSprite (&sprites[theme->flatsprites[COLOR_BLACK][PART_BISHOP]], 9.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'b') || (scene->gui.partspick_selectedpart == 'b')) ? 0xFF : 0x7F)); // black bishop  | 
        ||
| 830 | Render_DrawSprite (&sprites[theme->flatsprites[COLOR_BLACK][PART_KNIGHT]], 10.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'n') || (scene->gui.partspick_selectedpart == 'n')) ? 0xFF : 0x7F)); // black knight  | 
        ||
| 831 | Render_DrawSprite (&sprites[theme->flatsprites[COLOR_BLACK][PART_ROOK]], 11.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'r') || (scene->gui.partspick_selectedpart == 'r')) ? 0xFF : 0x7F)); // black rook  | 
        ||
| 832 | Render_DrawSprite (&sprites[theme->flatsprites[COLOR_BLACK][PART_PAWN]], 12.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'p') || (scene->gui.partspick_selectedpart == 'p')) ? 0xFF : 0x7F)); // black pawn  | 
        ||
| 833 | |||
| 834 | #undef PARTSIZE_PCT | 
        ||
| 835 |    } | 
        ||
| 836 | |||
| 837 |    // draw GUI texts | 
        ||
| 838 | DRAW_TEXT_IF_NEEDED (scene->gui.comment_text); // move comments  | 
        ||
| 839 | DRAW_TEXT_IF_NEEDED (scene->gui.history_text); // game history  | 
        ||
| 840 | DRAW_TEXT_IF_NEEDED (scene->gui.clock_text); // game clock  | 
        ||
| 841 | |||
| 842 |    // draw the chatter channels text | 
        ||
| 843 | Render_GetTextBoundaries (-1, chat_fontindex, L"a", &rect);  | 
        ||
| 124 | pmbaty | 844 | combinedheight_percent = (float) (rect.bottom * 100 / initial_height); // get a string's height  | 
        
| 1 | pmbaty | 845 | |
| 846 |    // cycle through all the chat strings... | 
        ||
| 847 | ccreply = NULL;  | 
        ||
| 848 | for (cchistory_index = 0; cchistory_index < scene->gui.cchistory_count; cchistory_index++)  | 
        ||
| 849 |    { | 
        ||
| 850 | ccreply = &scene->gui.cchistory[cchistory_index]; // quick access to CC reply  | 
        ||
| 851 | if ((ccreply->text[0] != 0) && (ccreply->arrival_time + 60.0f > current_time))  | 
        ||
| 852 | break; // break at the first one that we should display  | 
        ||
| 853 |    } | 
        ||
| 854 | |||
| 855 |    // have we some to display ? | 
        ||
| 856 | if (cchistory_index < scene->gui.cchistory_count)  | 
        ||
| 857 |    { | 
        ||
| 858 |       // first, get the remaining text's combined height | 
        ||
| 859 | for (cchistory_index2 = cchistory_index; cchistory_index2 < scene->gui.cchistory_count; cchistory_index2++)  | 
        ||
| 860 |       { | 
        ||
| 861 | ccreply = &scene->gui.cchistory[cchistory_index2]; // quick access to CC reply  | 
        ||
| 862 | |||
| 124 | pmbaty | 863 | combinedwidth_percent = 1.0f;  | 
        
| 864 | Render_GetTextBoundaries (100 - combinedwidth_percent, chat_fontindex, L"[] : ", &rect);  | 
        ||
| 865 | combinedwidth_percent += (float) (rect.right * 100 / initial_width);  | 
        ||
| 866 | Render_GetTextBoundaries (100 - combinedwidth_percent, chat_fontindex, ccreply->channelname, &rect);  | 
        ||
| 867 | combinedwidth_percent += (float) (rect.right * 100 / initial_width);  | 
        ||
| 868 | Render_GetTextBoundaries (100 - combinedwidth_percent, chat_fontindex, ccreply->nickname, &rect);  | 
        ||
| 869 | combinedwidth_percent += (float) (rect.right * 100 / initial_width);  | 
        ||
| 870 | Render_GetTextBoundaries (100 - combinedwidth_percent, chat_fontindex, ccreply->text, &rect);  | 
        ||
| 871 | combinedheight_percent += (float) (rect.bottom * 100 / initial_height); // add this string's height  | 
        ||
| 1 | pmbaty | 872 |       } | 
        
| 873 | |||
| 874 |       // now for each string remaining... | 
        ||
| 875 | for (; cchistory_index < scene->gui.cchistory_count; cchistory_index++)  | 
        ||
| 876 |       { | 
        ||
| 877 | ccreply = &scene->gui.cchistory[cchistory_index]; // quick access to CC reply  | 
        ||
| 878 | rect.right = 10;  | 
        ||
| 879 | PRINT_CCREPLY (ccreply); // print CC reply on screen  | 
        ||
| 124 | pmbaty | 880 | combinedheight_percent -= (float) ((rect.bottom - rect.top) * 100 / initial_height); // draw it from top of zone to bottom  | 
        
| 1 | pmbaty | 881 |       } | 
        
| 882 |    } | 
        ||
| 883 | |||
| 884 |    // are we online ? | 
        ||
| 885 | if (Player_FindByType (PLAYER_INTERNET) != NULL)  | 
        ||
| 886 |    { | 
        ||
| 887 | ccreply = &scene->gui.entered_ccreply;  | 
        ||
| 888 | if (!scene->gui.is_entering_text)  | 
        ||
| 889 | ccreply->color = RGBACOLOR_SETALPHA (ccreply->color, RGBACOLOR_ALPHA (ccreply->color) / 6); // if there's no text being entered, fade CC reply a lot  | 
        ||
| 890 | |||
| 891 | rect.right = 10;  | 
        ||
| 892 | PRINT_CCREPLY (ccreply); // print CC reply on screen  | 
        ||
| 893 |    } | 
        ||
| 894 | |||
| 895 |    // print GUI texts | 
        ||
| 896 | DRAW_TEXT_IF_NEEDED (scene->gui.turn_text); // player turn's text  | 
        ||
| 897 | DRAW_TEXT_IF_NEEDED (scene->gui.central_text); // central notification zone text  | 
        ||
| 898 | |||
| 899 |    // if needed, print the spinning wheel | 
        ||
| 900 | if (scene->gui.want_spinwheel)  | 
        ||
| 901 | Render_DrawSprite (&sprites[spinner_spriteindex[(int) (10.0f * current_time) % 12]], 47.0f, 46.0f, 6.0f, 8.0f, 255);  | 
        ||
| 902 | |||
| 903 |    // are we in demo mode ? if so, display the program name as a watermark | 
        ||
| 14 | pmbaty | 904 | if (!is_registered)  | 
        
| 124 | pmbaty | 905 | Render_wprintf (50.0f, 60.0f, 0.0f, ALIGN_CENTER, ALIGN_CENTER, ALIGN_CENTER, chat_fontindex,  | 
        
| 18 | pmbaty | 906 | D3DCOLOR_RGBA (255, 255, 255, 255),  | 
        
| 14 | pmbaty | 907 | NULL, PROGRAM_NAME L"%s - " PROGRAM_URL L"\n- %d:%02d -", LOCALIZE (L"EvaluationMode"), (int) (DEMO_TIMEOUT - current_time) / 60, (int) (DEMO_TIMEOUT - current_time) % 60);  | 
        
| 1 | pmbaty | 908 | |
| 909 |    // end 3D rendering on the back buffer | 
        ||
| 910 |    ////////////////////////////////////// | 
        ||
| 911 | |||
| 912 | d3ddev->EndScene (); // ends the 3D scene  | 
        ||
| 913 | d3ddev->Present (NULL, NULL, NULL, NULL); // displays the created frame on the screen  | 
        ||
| 914 | |||
| 915 |    // update the frame rate | 
        ||
| 916 | if (framerate_time < current_time)  | 
        ||
| 917 |    { | 
        ||
| 918 | framerate_value = framerate_count;  | 
        ||
| 919 | framerate_count = 0;  | 
        ||
| 920 | framerate_time = current_time + 1.0f;  | 
        ||
| 921 |    } | 
        ||
| 922 | framerate_count++; // one frame more elapsed  | 
        ||
| 923 | |||
| 924 | return; // finished  | 
        ||
| 925 | } | 
        ||
| 926 | |||
| 927 | |||
| 928 | int Render_LoadMesh (const wchar_t *fmt, ...)  | 
        ||
| 929 | { | 
        ||
| 930 |    // this function appends a new mesh in the global meshes buffer and returns its index | 
        ||
| 931 | |||
| 932 | static wchar_t meshfile_pathname[MAX_PATH];  | 
        ||
| 933 | unsigned long hash;  | 
        ||
| 934 | mesh_t *mesh;  | 
        ||
| 935 | int mesh_index;  | 
        ||
| 936 | va_list argptr;  | 
        ||
| 937 | |||
| 938 |    // concatenate all the arguments in one string | 
        ||
| 939 | va_start (argptr, fmt);  | 
        ||
| 940 | wvsprintf (meshfile_pathname, fmt, argptr);  | 
        ||
| 941 | va_end (argptr);  | 
        ||
| 942 | |||
| 943 |    // resolve wildcards and get content hash | 
        ||
| 944 | ResolveWildcard (meshfile_pathname, L".obj");  | 
        ||
| 945 | hash = HashFile (meshfile_pathname);  | 
        ||
| 946 | |||
| 947 |    // now cycle through all our loaded meshes and see if it's already loaded | 
        ||
| 948 | for (mesh_index = 0; mesh_index < mesh_count; mesh_index++)  | 
        ||
| 949 | if (meshes[mesh_index].hash == hash)  | 
        ||
| 950 | return (mesh_index); // if we can find it, return its index so as not to load it twice  | 
        ||
| 951 | |||
| 952 |    // reallocate space to hold one mesh more | 
        ||
| 953 | meshes = (mesh_t *) SAFE_realloc (meshes, mesh_count, mesh_count + 1, sizeof (mesh_t), false);  | 
        ||
| 954 | mesh = &meshes[mesh_count]; // quick access to the mesh we'll be working on  | 
        ||
| 955 | |||
| 956 |    // load the mesh | 
        ||
| 957 | if (!Render_LoadMesh_Obj (mesh, meshfile_pathname))  | 
        ||
| 958 | return (-1); // bomb out on error  | 
        ||
| 959 | |||
| 960 | mesh->hash = hash; // save the hash  | 
        ||
| 961 | mesh_count++; // we know now one mesh more  | 
        ||
| 962 | return (mesh_count - 1); // return its index  | 
        ||
| 963 | } | 
        ||
| 964 | |||
| 965 | |||
| 966 | int Render_LoadTexture (const wchar_t *fmt, ...)  | 
        ||
| 967 | { | 
        ||
| 968 |    // this function appends a new texture in the global textures buffer and returns its index | 
        ||
| 969 | |||
| 970 |    D3DSURFACE_DESC texture_description; | 
        ||
| 971 | wchar_t texturefile_pathname[MAX_PATH];  | 
        ||
| 972 | static wchar_t *filename;  | 
        ||
| 973 | unsigned long hash;  | 
        ||
| 974 | int texture_index;  | 
        ||
| 975 | va_list argptr;  | 
        ||
| 976 | |||
| 977 |    // concatenate all the arguments in one string | 
        ||
| 978 | va_start (argptr, fmt);  | 
        ||
| 979 | wvsprintf (texturefile_pathname, fmt, argptr);  | 
        ||
| 980 | va_end (argptr);  | 
        ||
| 981 | |||
| 982 |    // resolve wildcards and get content hash | 
        ||
| 983 | ResolveWildcard (texturefile_pathname, L".dds|.jpg|.jpeg|.png|.tga|.bmp");  | 
        ||
| 984 | hash = HashFile (texturefile_pathname);  | 
        ||
| 985 | |||
| 986 |    // now cycle through all our loaded textures and see if it's already loaded | 
        ||
| 987 | for (texture_index = 0; texture_index < texture_count; texture_index++)  | 
        ||
| 988 | if (textures[texture_index].hash == hash)  | 
        ||
| 989 | return (texture_index); // if we can find it, return its index so as not to load it twice  | 
        ||
| 990 | |||
| 991 |    // reallocate space to hold one texture more | 
        ||
| 992 | textures = (texture_t *) SAFE_realloc (textures, texture_count, texture_count + 1, sizeof (texture_t), false);  | 
        ||
| 993 | |||
| 994 |    // ask Direct3D to prepare texture data | 
        ||
| 995 | if (FAILED (D3DXCreateTextureFromFile (d3ddev, texturefile_pathname, &textures[texture_count].texture)))  | 
        ||
| 996 |    { | 
        ||
| 997 | MessageBox (NULL, LOCALIZE (L"Error_UnableToAddTextureD3DXCreateTextureFromFileFailed"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK);  | 
        ||
| 11 | pmbaty | 998 | terminate_everything = true; // this is a fatal error  | 
        
| 1 | pmbaty | 999 | return (-1); // bomb out on error  | 
        
| 1000 |    } | 
        ||
| 1001 | |||
| 1002 |    // get info on the newly loaded texture such as size etc. | 
        ||
| 1003 | textures[texture_count].texture->GetLevelDesc (0, &texture_description);  | 
        ||
| 1004 | textures[texture_count].width = texture_description.Width; // save texture width (as loaded)  | 
        ||
| 1005 | textures[texture_count].height = texture_description.Height; // save texture height (as loaded)  | 
        ||
| 1006 | textures[texture_count].hash = hash; // save its hash  | 
        ||
| 1007 | texture_count++; // we know now one texture more  | 
        ||
| 1008 | return (texture_count - 1); // return its index  | 
        ||
| 1009 | } | 
        ||
| 1010 | |||
| 1011 | |||
| 1012 | int Render_LoadFont (const wchar_t *font_name, int font_size, bool is_bold, bool is_italic)  | 
        ||
| 1013 | { | 
        ||
| 1014 |    // this function appends a new font in the global fonts buffer and returns its index | 
        ||
| 1015 | |||
| 1016 | unsigned long pathname_hash;  | 
        ||
| 1017 | int font_index;  | 
        ||
| 1018 | |||
| 1019 |    // first, get the hash of the requested pathname (include font size and weight parameters) | 
        ||
| 1020 | pathname_hash = HashString (font_name);  | 
        ||
| 1021 | pathname_hash += 3 * (unsigned long) font_size + 2 * (unsigned long) is_bold + (unsigned long) is_italic;  | 
        ||
| 1022 | |||
| 1023 |    // now cycle through all our loaded fonts and see if it's already loaded | 
        ||
| 1024 | for (font_index = 0; font_index < font_count; font_index++)  | 
        ||
| 1025 | if (fonts[font_index].pathname_hash == pathname_hash)  | 
        ||
| 1026 | return (font_index); // if we can find it, return its index so as not to load it twice  | 
        ||
| 1027 | |||
| 1028 |    // reallocate space to hold one font more | 
        ||
| 1029 | fonts = (font_t *) SAFE_realloc (fonts, font_count, font_count + 1, sizeof (font_t), false);  | 
        ||
| 1030 | |||
| 1031 |    // create a Direct3D font object and record font data | 
        ||
| 1032 | if (FAILED (D3DXCreateFont (d3ddev, font_size, // font height  | 
        ||
| 12 | pmbaty | 1033 | 2 * font_size / 5, // font width  | 
        
| 1 | pmbaty | 1034 | (is_bold ? FW_BOLD : FW_NORMAL), // font weight (bold, etc)  | 
        
| 1035 | 0, // miplevels  | 
        ||
| 1036 |                                is_italic, // is italic | 
        ||
| 1037 |                                DEFAULT_CHARSET, // charset | 
        ||
| 1038 |                                OUT_DEFAULT_PRECIS, // precision | 
        ||
| 1039 |                                CLEARTYPE_QUALITY, // font quality (antialiased or not) | 
        ||
| 1040 | DEFAULT_PITCH | FF_DONTCARE, // font family  | 
        ||
| 1041 |                                font_name, // font name | 
        ||
| 1042 | &fonts[font_count].font))) // and a pointer that will receive the font  | 
        ||
| 1043 |    { | 
        ||
| 1044 | MessageBox (NULL, LOCALIZE (L"Error_UnableToAddFontD3DXCreateFontFailed"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK);  | 
        ||
| 11 | pmbaty | 1045 | terminate_everything = true; // this is a fatal error  | 
        
| 1 | pmbaty | 1046 | return (-1); // bomb out on error  | 
        
| 1047 |    } | 
        ||
| 1048 | |||
| 1049 | fonts[font_count].pathname_hash = pathname_hash; // save its hash  | 
        ||
| 1050 | font_count++; // we know now one font more  | 
        ||
| 1051 | return (font_count - 1); // return its index  | 
        ||
| 1052 | } | 
        ||
| 1053 | |||
| 1054 | |||
| 1055 | int Render_LoadSprite (const wchar_t *fmt, ...)  | 
        ||
| 1056 | { | 
        ||
| 1057 |    // this function appends a new sprite in the global sprites buffer and returns its index | 
        ||
| 1058 | |||
| 1059 | wchar_t spritefile_pathname[MAX_PATH];  | 
        ||
| 1060 | unsigned long hash;  | 
        ||
| 1061 | int sprite_index;  | 
        ||
| 1062 | va_list argptr;  | 
        ||
| 1063 | |||
| 1064 |    // concatenate all the arguments in one string | 
        ||
| 1065 | va_start (argptr, fmt);  | 
        ||
| 1066 | wvsprintf (spritefile_pathname, fmt, argptr);  | 
        ||
| 1067 | va_end (argptr);  | 
        ||
| 1068 | |||
| 1069 |    // resolve wildcards and get content hash | 
        ||
| 1070 | ResolveWildcard (spritefile_pathname, L".dds|.jpg|.jpeg|.png|.tga|.bmp");  | 
        ||
| 1071 | hash = HashFile (spritefile_pathname);  | 
        ||
| 1072 | |||
| 1073 |    // now cycle through all our loaded sprites and see if it's already loaded | 
        ||
| 1074 | for (sprite_index = 0; sprite_index < sprite_count; sprite_index++)  | 
        ||
| 1075 | if (sprites[sprite_index].hash == hash)  | 
        ||
| 1076 | return (sprite_index); // if we can find it, return its index so as not to load it twice  | 
        ||
| 1077 | |||
| 1078 |    // reallocate space to hold one sprite more | 
        ||
| 1079 | sprites = (sprite_t *) SAFE_realloc (sprites, sprite_count, sprite_count + 1, sizeof (sprite_t), false);  | 
        ||
| 1080 | |||
| 1081 |    // ask Direct3D to prepare texture data | 
        ||
| 1082 | if (FAILED (D3DXCreateSprite (d3ddev, &sprites[sprite_count].sprite)))  | 
        ||
| 1083 |    { | 
        ||
| 1084 | MessageBox (NULL, LOCALIZE (L"Error_UnableToAddSpriteD3DXCreateSpriteFailed"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK);  | 
        ||
| 11 | pmbaty | 1085 | terminate_everything = true; // this is a fatal error  | 
        
| 1 | pmbaty | 1086 | return (-1); // bomb out on error  | 
        
| 1087 |    } | 
        ||
| 1088 | sprites[sprite_count].texture_index = Render_LoadTexture (spritefile_pathname); // register and save sprite texture  | 
        ||
| 1089 | sprites[sprite_count].hash = hash; // save its hash  | 
        ||
| 1090 | |||
| 1091 | sprite_count++; // we know now one sprite more  | 
        ||
| 1092 | return (sprite_count - 1); // return its index  | 
        ||
| 1093 | } | 
        ||
| 1094 | |||
| 1095 | |||
| 1096 | int Render_MaterialIndexOf (const wchar_t *material_name)  | 
        ||
| 1097 | { | 
        ||
| 1098 |    // this function returns the index of the material in the global materials array which has the specified name | 
        ||
| 1099 | |||
| 1100 | int material_index;  | 
        ||
| 1101 | |||
| 1102 |    // cycle through all materials and look whether one with the specified name exists | 
        ||
| 1103 | for (material_index = 0; material_index < material_count; material_index++)  | 
        ||
| 1104 | if (_wcsicmp (materials[material_index].name, material_name) == 0)  | 
        ||
| 1105 | return (material_index); // if we find one, return its index  | 
        ||
| 1106 | |||
| 1107 | return (material_count - 1); // else return the index of the last material in list, which is the default material  | 
        ||
| 1108 | } | 
        ||
| 1109 | |||
| 1110 | |||
| 1111 | void Render_MouseToFloor (short mouse_x, short mouse_y, float *floor_x, float *floor_y)  | 
        ||
| 1112 | { | 
        ||
| 1113 |    // this function converts a mouse coordinates into floor coordinates by doing vector | 
        ||
| 1114 |    // projection on the floor plane from the eyepoint of the camera | 
        ||
| 1115 | |||
| 1116 | static D3DXPLANE floor_plane;  | 
        ||
| 1117 | static bool is_planefound = false;  | 
        ||
| 1118 | |||
| 1119 |    D3DXMATRIX projection_matrix; | 
        ||
| 1120 |    D3DXMATRIX view_matrix; | 
        ||
| 1121 |    D3DXMATRIX invertedview_matrix; | 
        ||
| 1122 | float mouse_pitch;  | 
        ||
| 1123 | float mouse_yaw;  | 
        ||
| 1124 |    vector_t v_lookat; | 
        ||
| 1125 |    vector_t v_intersection; | 
        ||
| 1126 | |||
| 1127 |    // find the floor plane (only do it once) | 
        ||
| 1128 | if (!is_planefound)  | 
        ||
| 1129 |    { | 
        ||
| 131 | pmbaty | 1130 | D3DXPlaneFromPointNormal (&floor_plane, (D3DXVECTOR3 *) &scene_lookatpoint, (D3DXVECTOR3 *) &upwards_direction);  | 
        
| 1 | pmbaty | 1131 | is_planefound = true; // once and for all, as this plane will never change  | 
        
| 1132 |    } | 
        ||
| 1133 | |||
| 1134 |    // get the current projection and view matrices, and invert the view matrix | 
        ||
| 1135 | d3ddev->GetTransform (D3DTS_PROJECTION, &projection_matrix);  | 
        ||
| 1136 | d3ddev->GetTransform (D3DTS_VIEW, &view_matrix);  | 
        ||
| 1137 | D3DXMatrixInverse (&invertedview_matrix, NULL, &view_matrix);  | 
        ||
| 1138 | |||
| 1139 |    // convert the mouse coordinates to relative pitch and yaw | 
        ||
| 1140 | mouse_pitch = (((mouse_x * 2.0f) / current_width) - 1) / projection_matrix._11;  | 
        ||
| 1141 | mouse_yaw = -(((mouse_y * 2.0f) / current_height) - 1) / projection_matrix._22;  | 
        ||
| 1142 | |||
| 1143 |    // now build a matrix that will describe the mouse direction vector, add it to the camera position, and make it 200 times longer | 
        ||
| 1144 | v_lookat.x = camera_position.x + (mouse_pitch * invertedview_matrix._11 + mouse_yaw * invertedview_matrix._21 + invertedview_matrix._31) * 200.0f;  | 
        ||
| 1145 | v_lookat.y = camera_position.y + (mouse_pitch * invertedview_matrix._12 + mouse_yaw * invertedview_matrix._22 + invertedview_matrix._32) * 200.0f;  | 
        ||
| 1146 | v_lookat.z = camera_position.z + (mouse_pitch * invertedview_matrix._13 + mouse_yaw * invertedview_matrix._23 + invertedview_matrix._33) * 200.0f;  | 
        ||
| 1147 | |||
| 1148 |    // and the intersection point with our ray | 
        ||
| 1149 | D3DXPlaneIntersectLine ((D3DXVECTOR3 *) &v_intersection, &floor_plane, (D3DXVECTOR3 *) &camera_position, (D3DXVECTOR3 *) &v_lookat);  | 
        ||
| 1150 | |||
| 1151 |    // now fill the return values | 
        ||
| 1152 | *floor_x = v_intersection.x;  | 
        ||
| 1153 | *floor_y = v_intersection.y;  | 
        ||
| 1154 | |||
| 1155 | return; // finished  | 
        ||
| 1156 | } | 
        ||
| 1157 | |||
| 1158 | |||
| 1159 | bool Render_IsMouseInBox (short mouse_x, short mouse_y, float x_percent, float y_percent, float width_percent, float height_percent)  | 
        ||
| 1160 | { | 
        ||
| 1161 |    // helper function that returns whether the mouse coordinates are inside a given square | 
        ||
| 1162 | |||
| 1163 | float mousex_percent;  | 
        ||
| 1164 | float mousey_percent;  | 
        ||
| 1165 | |||
| 1166 |    // compute mouse coordinates in percents | 
        ||
| 136 | pmbaty | 1167 | mousex_percent = (float) mouse_x * 100.0f / current_width;  | 
        
| 1168 | mousey_percent = (float) mouse_y * 100.0f / current_height;  | 
        ||
| 1 | pmbaty | 1169 | |
| 1170 | return ((mousex_percent >= x_percent) && (mousex_percent <= x_percent + width_percent)  | 
        ||
| 1171 | && (mousey_percent >= y_percent) && (mousey_percent <= y_percent + height_percent));  | 
        ||
| 1172 | } | 
        ||
| 1173 | |||
| 1174 | |||
| 1175 | static bool Render_LoadMesh_Obj (mesh_t *mesh, const wchar_t *objfile_pathname)  | 
        ||
| 1176 | { | 
        ||
| 1177 |    // this function loads a mesh from a Wavefront Object file (.obj) | 
        ||
| 1178 | |||
| 1179 |    #define OBJ_INCREASE_OR_RESIZE(count,maxcount,increment,arrayptr,type,erase) { \ | 
        ||
| 1180 |       (count)++; \ | 
        ||
| 1181 |       if ((count) == (maxcount)) \ | 
        ||
| 1182 |       { \ | 
        ||
| 1183 |          (arrayptr) = (type *) SAFE_realloc ((arrayptr), (maxcount), (maxcount) + (increment), sizeof (type), erase); \ | 
        ||
| 1184 |          (maxcount) += (increment); \ | 
        ||
| 1185 |       } \ | 
        ||
| 1186 |    } | 
        ||
| 1187 |    #define OBJ_CONVERT_INDEX(element,current_element_count) if ((element) < 0) (element) = (current_element_count) + (element); else (element)--; | 
        ||
| 1188 |    #define OBJ_GET_EXISTING_INDEX_OR_APPEND_VERTEX(uniquevertex) \ | 
        ||
| 1189 |    { \ | 
        ||
| 1190 |       hash = &hashtable[*((unsigned long *) &obj.vs[(uniquevertex).iv].x) & 0xFF]; \ | 
        ||
| 1191 |       for (vertex_index = 0; vertex_index < hash->count; vertex_index++) \ | 
        ||
| 1192 |          if ((memcmp (&vertices[hash->indices[vertex_index]].position, &obj.vs[(uniquevertex).iv], sizeof (vector_t)) == 0) \ | 
        ||
| 1193 |              && (memcmp (&vertices[hash->indices[vertex_index]].normal, &obj.ns[(uniquevertex).in], sizeof (vector_t)) == 0) \ | 
        ||
| 1194 |              && (memcmp (&vertices[hash->indices[vertex_index]].texcoord, &obj.tcs[(uniquevertex).itc], sizeof (texcoord_t)) == 0)) \ | 
        ||
| 1195 |             break; \ | 
        ||
| 1196 |       if (vertex_index == hash->count) \ | 
        ||
| 1197 |       { \ | 
        ||
| 1198 |          vertex_index = mesh->vertice_count; \ | 
        ||
| 1199 |          current_vertex = &vertices[vertex_index]; \ | 
        ||
| 1200 |          memset (current_vertex, 0, sizeof (vertex_t)); \ | 
        ||
| 1201 |          memcpy (¤t_vertex->position, &obj.vs[(uniquevertex).iv], sizeof (vector_t)); \ | 
        ||
| 1202 |          if ((uniquevertex).in > -1) \ | 
        ||
| 1203 |             memcpy (¤t_vertex->normal, &obj.ns[(uniquevertex).in], sizeof (vector_t)); \ | 
        ||
| 1204 |          if ((uniquevertex).itc > -1) \ | 
        ||
| 1205 |             memcpy (¤t_vertex->texcoord, &obj.tcs[(uniquevertex).itc], sizeof (texcoord_t)); \ | 
        ||
| 1206 |          hash = &hashtable[*((unsigned long *) ¤t_vertex->normal.x) & 0xFF]; \ | 
        ||
| 1207 |          hash->indices = (long *) SAFE_realloc (hash->indices, hash->count, hash->count + 1, sizeof (long), false); \ | 
        ||
| 1208 |          hash->indices[hash->count] = vertex_index; \ | 
        ||
| 1209 |          hash->count++; \ | 
        ||
| 1210 |          mesh->vertice_count++; \ | 
        ||
| 1211 |       } \ | 
        ||
| 1212 |       else \ | 
        ||
| 1213 |          vertex_index = hash->indices[vertex_index]; \ | 
        ||
| 1214 |    } | 
        ||
| 1215 | |||
| 1216 | typedef struct obj_uniquevertex_s { long iv, in, itc; } obj_uniquevertex_t;  | 
        ||
| 1217 | typedef struct obj_face_s { obj_uniquevertex_t v1, v2, v3; } obj_face_t;  | 
        ||
| 1218 | typedef struct obj_hashbucket_s { int count; long *indices; /* mallocated */ } obj_hashbucket_t;  | 
        ||
| 1219 | typedef struct objfile_s  | 
        ||
| 1220 |    { | 
        ||
| 1221 | vector_t *vs; long v_count; long v_maxcount; // array mallocated to v_maxcount  | 
        ||
| 1222 | vector_t *ns; long n_count; long n_maxcount; // array mallocated to n_maxcount  | 
        ||
| 1223 | texcoord_t *tcs; long tc_count; long tc_maxcount; // array mallocated to tc_maxcount  | 
        ||
| 1224 | obj_face_t *fs; long f_count; long f_maxcount; // array mallocated to f_maxcount  | 
        ||
| 1225 | } objfile_t;  | 
        ||
| 1226 | |||
| 1227 | static obj_hashbucket_t hashtable[256];  | 
        ||
| 1228 |    objfile_t obj; | 
        ||
| 1229 | obj_hashbucket_t *hash;  | 
        ||
| 1230 | obj_face_t *f;  | 
        ||
| 1231 | vertex_t *vertices; // mallocated  | 
        ||
| 1232 | unsigned long *indices; // mallocated  | 
        ||
| 1233 | vertex_t *current_vertex;  | 
        ||
| 81 | pmbaty | 1234 | unsigned long file_size;  | 
        
| 1 | pmbaty | 1235 | char *filedata; // mallocated  | 
        
| 1236 | char *fileptr;  | 
        ||
| 1237 | int vertex_index;  | 
        ||
| 1238 | int array_index;  | 
        ||
| 1239 | void *ptr_to;  | 
        ||
| 1240 | FILE *fp;  | 
        ||
| 1241 | |||
| 1242 |    // open the mesh file and read it as a whole | 
        ||
| 1243 | _wfopen_s (&fp, objfile_pathname, L"rb");  | 
        ||
| 1244 | if (fp == NULL)  | 
        ||
| 1245 | return (false); // bomb out on error  | 
        ||
| 81 | pmbaty | 1246 | fseek (fp, 0, SEEK_END); // seek at end of file...  | 
        
| 1247 | file_size = ftell (fp); // ...read file length...  | 
        ||
| 1248 | fseek (fp, 0, SEEK_SET); // and rewind  | 
        ||
| 1249 | filedata = (char *) SAFE_malloc (file_size, sizeof (char), false); // mallocate space for data  | 
        ||
| 1250 | fread (filedata, file_size, 1, fp); // read file as a whole  | 
        ||
| 1 | pmbaty | 1251 | fclose (fp); // file is read, close it  | 
        
| 1252 | |||
| 1253 |    // allocate space for an arbitrary amount of vertices, texture coordinates, normals and faces | 
        ||
| 1254 | memset (&obj, 0, sizeof (obj));  | 
        ||
| 1255 | obj.v_maxcount = 10000; obj.vs = (vector_t *) SAFE_malloc (obj.v_maxcount, sizeof (vector_t), false);  | 
        ||
| 1256 | obj.n_maxcount = 10000; obj.ns = (vector_t *) SAFE_malloc (obj.n_maxcount, sizeof (vector_t), false);  | 
        ||
| 1257 | obj.tc_maxcount = 10000; obj.tcs = (texcoord_t *) SAFE_malloc (obj.tc_maxcount, sizeof (texcoord_t), false);  | 
        ||
| 1258 | obj.f_maxcount = 5000; obj.fs = (obj_face_t *) SAFE_malloc (obj.f_maxcount, sizeof (obj_face_t), true); // zero out the faces array (IMPORTANT !)  | 
        ||
| 1259 | |||
| 1260 |    // read file line per line... | 
        ||
| 1261 | fileptr = filedata - 1; // start parsing line after line  | 
        ||
| 1262 | while (fileptr != NULL)  | 
        ||
| 1263 |    { | 
        ||
| 1264 | fileptr++; // skip the line feed (or reach the first character, if it's the first pass)  | 
        ||
| 1265 | |||
| 1266 |       // is it a vertex-related line ? | 
        ||
| 1267 | if (fileptr[0] == L'v')  | 
        ||
| 1268 |       { | 
        ||
| 1269 |          // is it a vertex, a normal or a texture coordinate ? | 
        ||
| 1270 | if ((fileptr[1] == L' ') && (sscanf_s (&fileptr[2], "%f %f %f", &obj.vs[obj.v_count].x, &obj.vs[obj.v_count].y, &obj.vs[obj.v_count].z) == 3))  | 
        ||
| 1271 | OBJ_INCREASE_OR_RESIZE (obj.v_count, obj.v_maxcount, 10000, obj.vs, vector_t, false) // one vertex more has been read  | 
        ||
| 1272 | else if ((fileptr[1] == L'n') && (sscanf_s (&fileptr[3], "%f %f %f", &obj.ns[obj.n_count].x, &obj.ns[obj.n_count].y, &obj.ns[obj.n_count].z) == 3))  | 
        ||
| 1273 | OBJ_INCREASE_OR_RESIZE (obj.n_count, obj.n_maxcount, 10000, obj.ns, vector_t, false) // one normal more has been read  | 
        ||
| 1274 | else if ((fileptr[1] == L't') && (sscanf_s (&fileptr[3], "%f %f", &obj.tcs[obj.tc_count].u, &obj.tcs[obj.tc_count].v) == 2))  | 
        ||
| 1275 | OBJ_INCREASE_OR_RESIZE (obj.tc_count, obj.tc_maxcount, 10000, obj.tcs, texcoord_t, false) // one texture coordinate more has been read  | 
        ||
| 1276 |       } | 
        ||
| 1277 | |||
| 1278 |       // else is it a face-related line ? | 
        ||
| 1279 | else if (fileptr[0] == L'f')  | 
        ||
| 1280 |       { | 
        ||
| 1281 |          // get a quick pointer to current face (note: it's been already blanked out by malloc()) | 
        ||
| 1282 | f = &obj.fs[obj.f_count];  | 
        ||
| 1283 | |||
| 1284 |          // is it a face with normals, a face without normals or a face without normals and texture coordinates ? | 
        ||
| 1285 | if ((sscanf_s (&fileptr[2], "%d/%d/%d %d/%d/%d %d/%d/%d", &f->v1.iv, &f->v1.itc, &f->v1.in, &f->v2.iv, &f->v2.itc, &f->v2.in, &f->v3.iv, &f->v3.itc, &f->v3.in) == 9)  | 
        ||
| 1286 | || (sscanf_s (&fileptr[2], "%d/%d %d/%d %d/%d", &f->v3.iv, &f->v3.itc, &f->v2.iv, &f->v2.itc, &f->v3.iv, &f->v3.itc) == 6)  | 
        ||
| 1287 | || (sscanf_s (&fileptr[2], "%d %d %d", &f->v3.iv, &f->v2.iv, &f->v3.iv) == 6))  | 
        ||
| 1288 |          { | 
        ||
| 1289 | OBJ_CONVERT_INDEX (f->v1.iv, obj.v_count);  | 
        ||
| 1290 | OBJ_CONVERT_INDEX (f->v1.in, obj.n_count); // if no normal could be read, its index will be converted from 0 to -1  | 
        ||
| 1291 | OBJ_CONVERT_INDEX (f->v1.itc, obj.tc_count); // if no texcoord could be read, its index will be converted from 0 to -1  | 
        ||
| 1292 | OBJ_CONVERT_INDEX (f->v2.iv, obj.v_count);  | 
        ||
| 1293 | OBJ_CONVERT_INDEX (f->v2.in, obj.n_count); // if no normal could be read, its index will be converted from 0 to -1  | 
        ||
| 1294 | OBJ_CONVERT_INDEX (f->v2.itc, obj.tc_count); // if no texcoord could be read, its index will be converted from 0 to -1  | 
        ||
| 1295 | OBJ_CONVERT_INDEX (f->v3.iv, obj.v_count);  | 
        ||
| 1296 | OBJ_CONVERT_INDEX (f->v3.in, obj.n_count); // if no normal could be read, its index will be converted from 0 to -1  | 
        ||
| 1297 | OBJ_CONVERT_INDEX (f->v3.itc, obj.tc_count); // if no texcoord could be read, its index will be converted from 0 to -1  | 
        ||
| 1298 | OBJ_INCREASE_OR_RESIZE (obj.f_count, obj.f_maxcount, 5000, obj.fs, obj_face_t, true) // one face more has been read  | 
        ||
| 1299 |          } | 
        ||
| 1300 |       } | 
        ||
| 1301 | |||
| 1302 | fileptr = strchr (fileptr, '\n'); // proceed to next line  | 
        ||
| 1303 |    } | 
        ||
| 1304 | |||
| 1305 |    // now build our final vertex and index list | 
        ||
| 1306 | vertices = (vertex_t *) SAFE_malloc (3 * obj.f_count, sizeof (vertex_t), false); // mallocate for the max number of vertices we can have  | 
        ||
| 1307 | indices = (unsigned long *) SAFE_malloc (3 * obj.f_count, sizeof (unsigned long), false); // mallocate for the right amount of indices  | 
        ||
| 1308 | |||
| 1309 |    // t3h mighty l00p ^^ (builds vertex and index buffers) | 
        ||
| 1310 | memset (hashtable, 0, sizeof (hashtable)); // wipe out the hashtable  | 
        ||
| 1311 | mesh->vertice_count = 0; // start with an unoptimized list  | 
        ||
| 1312 | for (array_index = 0; array_index < obj.f_count; array_index++)  | 
        ||
| 1313 |    { | 
        ||
| 1314 | f = &obj.fs[array_index]; // quick access to current face  | 
        ||
| 1315 | OBJ_GET_EXISTING_INDEX_OR_APPEND_VERTEX (f->v1);  | 
        ||
| 1316 | indices[3 * array_index + 0] = vertex_index;  | 
        ||
| 1317 | OBJ_GET_EXISTING_INDEX_OR_APPEND_VERTEX (f->v2);  | 
        ||
| 1318 | indices[3 * array_index + 1] = vertex_index;  | 
        ||
| 1319 | OBJ_GET_EXISTING_INDEX_OR_APPEND_VERTEX (f->v3);  | 
        ||
| 1320 | indices[3 * array_index + 2] = vertex_index;  | 
        ||
| 1321 |    } | 
        ||
| 1322 | |||
| 1323 |    // now create a correctly-sized DirectX vertex buffer and populate it | 
        ||
| 1324 | mesh->vertex_format = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;  | 
        ||
| 1325 | mesh->vertice_size = sizeof (vertex_t);  | 
        ||
| 1326 | d3ddev->CreateVertexBuffer (mesh->vertice_count * mesh->vertice_size, // length  | 
        ||
| 1327 |                                D3DUSAGE_DYNAMIC, // usage | 
        ||
| 1328 | mesh->vertex_format, // vertex format  | 
        ||
| 1329 |                                D3DPOOL_DEFAULT, // pool type | 
        ||
| 1330 | &mesh->d3dvertices, // pointer to the vertex buffer pointer  | 
        ||
| 1331 | NULL); // shared handle  | 
        ||
| 1332 | mesh->d3dvertices->Lock (0, mesh->vertice_count * mesh->vertice_size, &ptr_to, D3DLOCK_DISCARD);  | 
        ||
| 1333 | memcpy (ptr_to, vertices, mesh->vertice_count * mesh->vertice_size);  | 
        ||
| 1334 | mesh->d3dvertices->Unlock ();  | 
        ||
| 1335 | |||
| 1336 |    // create a correctly-sized DirectX index buffer and populate it | 
        ||
| 1337 | mesh->is_indexed = true; // remember that we're building an index buffer  | 
        ||
| 1338 | mesh->indice_count = obj.f_count * 3;  | 
        ||
| 1339 | mesh->indice_size = (mesh->indice_count <= (int) USHRT_MAX ? 2 : 4);  | 
        ||
| 1340 | d3ddev->CreateIndexBuffer (mesh->indice_count * mesh->indice_size, // length  | 
        ||
| 1341 |                               D3DUSAGE_DYNAMIC, // usage | 
        ||
| 1342 | (mesh->indice_size == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32), // format (here, 16 or 32-bit)  | 
        ||
| 1343 |                               D3DPOOL_DEFAULT, // pool type | 
        ||
| 1344 | &mesh->d3dindices, // pointer to the index buffer pointer  | 
        ||
| 1345 | NULL); // shared handle  | 
        ||
| 1346 | mesh->d3dindices->Lock (0, mesh->indice_count * mesh->indice_size, &ptr_to, D3DLOCK_DISCARD);  | 
        ||
| 1347 | if (mesh->indice_size == 2)  | 
        ||
| 1348 | for (array_index = 0; array_index < mesh->indice_count; array_index++)  | 
        ||
| 1349 | ((unsigned short *) ptr_to)[array_index] = (unsigned short) indices[array_index];  | 
        ||
| 1350 |    else | 
        ||
| 1351 | memcpy (ptr_to, indices, mesh->indice_count * mesh->indice_size);  | 
        ||
| 1352 | mesh->d3dindices->Unlock ();  | 
        ||
| 1353 | |||
| 1354 |    // finished, free the temporary objects | 
        ||
| 1355 | for (array_index = 0; array_index < sizeof (hashtable) / sizeof (obj_hashbucket_t); array_index++)  | 
        ||
| 1356 | SAFE_free ((void **) &hashtable[array_index].indices);  | 
        ||
| 1357 | SAFE_free ((void **) &indices);  | 
        ||
| 1358 | SAFE_free ((void **) &vertices);  | 
        ||
| 1359 | SAFE_free ((void **) &obj.vs);  | 
        ||
| 1360 | SAFE_free ((void **) &obj.ns);  | 
        ||
| 1361 | SAFE_free ((void **) &obj.tcs);  | 
        ||
| 1362 | SAFE_free ((void **) &obj.fs);  | 
        ||
| 1363 | SAFE_free ((void **) &filedata);  | 
        ||
| 1364 | |||
| 1365 | return (true); // Wavefront Object successfully loaded, return TRUE  | 
        ||
| 1366 | |||
| 1367 |    #undef OBJ_GET_EXISTING_INDEX_OR_APPEND_VERTEX | 
        ||
| 1368 |    #undef OBJ_CONVERT_INDEX | 
        ||
| 1369 |    #undef OBJ_INCREASE_OR_RESIZE | 
        ||
| 1370 | } | 
        ||
| 1371 | |||
| 1372 | |||
| 1373 | static void Render_DrawSceneObjectReflection (sceneobject_t *sceneobject)  | 
        ||
| 1374 | { | 
        ||
| 1375 |    // fast helper to draw a mesh at a specified location with certain pitch and yaw angles | 
        ||
| 1376 | |||
| 1377 |    D3DXMATRIX rotation_matrix; | 
        ||
| 1378 |    D3DXMATRIX translation_matrix; | 
        ||
| 1379 |    D3DXMATRIX reflect_matrix; | 
        ||
| 1380 |    D3DXMATRIX scaling_matrix; | 
        ||
| 1381 | material_t *material;  | 
        ||
| 1382 |    D3DMATERIAL9 d3dmaterial; | 
        ||
| 1383 |    D3DXPLANE plane; | 
        ||
| 1384 | mesh_t *mesh;  | 
        ||
| 1385 | mesh_t *tile_mesh;  | 
        ||
| 1386 | float alpha;  | 
        ||
| 1387 | |||
| 1388 |    // draw the reflection below this mesh | 
        ||
| 1389 | |||
| 1390 |    // quick access to meshes | 
        ||
| 1391 | mesh = &meshes[sceneobject->mesh_index];  | 
        ||
| 1392 | tile_mesh = &meshes[theme->tile_meshindex];  | 
        ||
| 1393 | |||
| 1394 |    // set the world transform at location | 
        ||
| 131 | pmbaty | 1395 | D3DXPlaneFromPointNormal (&plane, (D3DXVECTOR3 *) &scene_lookatpoint, (D3DXVECTOR3 *) &upwards_direction);  | 
        
| 1 | pmbaty | 1396 | D3DXMatrixReflect (&reflect_matrix, &plane);  | 
        
| 1397 | D3DXMatrixRotationYawPitchRoll (&rotation_matrix, -sceneobject->pitch * TO_RADIANS, 0.0f, -sceneobject->yaw * TO_RADIANS);  | 
        ||
| 1398 | D3DXMatrixTranslation (&translation_matrix, sceneobject->x, sceneobject->y, -sceneobject->z);  | 
        ||
| 1399 | D3DXMatrixScaling (&scaling_matrix, sceneobject->scale, sceneobject->scale, 1.0f);  | 
        ||
| 1400 | |||
| 1401 |    // tell Direct3D about our matrix | 
        ||
| 1402 | d3ddev->SetTransform (D3DTS_WORLD, &(reflect_matrix * scaling_matrix * rotation_matrix * translation_matrix));  | 
        ||
| 1403 | |||
| 1404 | d3ddev->SetRenderState (D3DRS_STENCILENABLE, true); // enable the stencil buffer  | 
        ||
| 1405 | d3ddev->SetRenderState (D3DRS_STENCILFUNC, D3DCMP_LESS); // instruct how to fill the stencil buffer  | 
        ||
| 1406 | d3ddev->SetRenderState (D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); // instruct how to fill the stencil buffer  | 
        ||
| 1407 | |||
| 1408 |    // set the texture for this mesh | 
        ||
| 1409 | if (sceneobject->texture_index != -1)  | 
        ||
| 1410 | d3ddev->SetTexture (0, textures[sceneobject->texture_index].texture);  | 
        ||
| 1411 |    else | 
        ||
| 1412 | d3ddev->SetTexture (0, NULL);  | 
        ||
| 1413 | |||
| 1414 |    // adjust the light reflection properties by setting the material | 
        ||
| 1415 | if (sceneobject->material_index != -1)  | 
        ||
| 1416 | material = &materials[sceneobject->material_index]; // use the specified scene object material  | 
        ||
| 1417 |    else | 
        ||
| 1418 | material = &materials[material_count - 1]; // scene object material unspecified, use default material  | 
        ||
| 1419 | alpha = theme->reflection_alpha / 256.0f;  | 
        ||
| 1420 | d3dmaterial.Ambient = D3DXCOLOR (material->ambient, material->ambient, material->ambient, material->transparency * alpha); // Alpha value not used according to SDK  | 
        ||
| 1421 | d3dmaterial.Diffuse = D3DXCOLOR (material->diffuse, material->diffuse, material->diffuse, material->transparency * alpha);  | 
        ||
| 1422 | d3dmaterial.Emissive = D3DXCOLOR (material->emissive, material->emissive, material->emissive, material->transparency * alpha); // Alpha value not used according to SDK  | 
        ||
| 1423 | d3dmaterial.Specular = D3DXCOLOR (material->specular, material->specular, material->specular, material->transparency * alpha); // Alpha value not used according to SDK  | 
        ||
| 1424 | d3dmaterial.Power = material->shininess;  | 
        ||
| 1425 | d3ddev->SetMaterial (&d3dmaterial);  | 
        ||
| 1426 | |||
| 1427 |    // draw the mesh subset | 
        ||
| 1428 | d3ddev->SetStreamSource (0, mesh->d3dvertices, 0, sizeof (vertex_t));  | 
        ||
| 1429 | d3ddev->SetFVF (mesh->vertex_format);  | 
        ||
| 1430 | d3ddev->SetRenderState (D3DRS_CULLMODE, D3DCULL_CW); // draw the faces backwards  | 
        ||
| 1431 | if (mesh->is_indexed)  | 
        ||
| 1432 |    { | 
        ||
| 1433 | d3ddev->SetIndices (mesh->d3dindices);  | 
        ||
| 1434 | d3ddev->DrawIndexedPrimitive (D3DPT_TRIANGLELIST, 0, 0, mesh->vertice_count, 0, mesh->indice_count / 3);  | 
        ||
| 1435 |    } | 
        ||
| 1436 |    else | 
        ||
| 1437 | d3ddev->DrawPrimitive (D3DPT_TRIANGLELIST, 0, mesh->vertice_count / 3);  | 
        ||
| 1438 | |||
| 1439 | d3ddev->SetRenderState (D3DRS_STENCILENABLE, false); // and disable the stencil buffer  | 
        ||
| 1440 | |||
| 1441 |    // now draw the simple shadow below this mesh | 
        ||
| 1442 | |||
| 1443 |    // grab the tools we need in hand | 
        ||
| 1444 | d3ddev->SetRenderState (D3DRS_ZENABLE, false); // disable the Z buffer  | 
        ||
| 1445 | d3ddev->SetRenderState (D3DRS_AMBIENT, D3DCOLOR_XRGB (255, 255, 255)); // raise ambient light  | 
        ||
| 1446 | |||
| 1447 |    // position the simple shadow sprite | 
        ||
| 1448 | D3DXMatrixScaling (&scaling_matrix, max (sceneobject->simpleshadow_size, sceneobject->z / 5.0f), max (sceneobject->simpleshadow_size, sceneobject->z / 5.0f), 0.0f);  | 
        ||
| 1449 | D3DXMatrixTranslation (&translation_matrix, sceneobject->x, sceneobject->y, 0.0f);  | 
        ||
| 1450 | d3ddev->SetTransform (D3DTS_WORLD, &(scaling_matrix * translation_matrix));  | 
        ||
| 1451 | |||
| 1452 |    // adjust the light reflection properties by setting the material | 
        ||
| 1453 | material = &materials[material_count - 1]; // use the default material  | 
        ||
| 1454 | d3dmaterial.Ambient = D3DXCOLOR (material->ambient, material->ambient, material->ambient, material->transparency);  | 
        ||
| 1455 | d3dmaterial.Diffuse = D3DXCOLOR (material->diffuse, material->diffuse, material->diffuse, material->transparency);  | 
        ||
| 1456 | d3dmaterial.Emissive = D3DXCOLOR (material->emissive, material->emissive, material->emissive, material->transparency);  | 
        ||
| 1457 | d3dmaterial.Specular = D3DXCOLOR (material->specular, material->specular, material->specular, material->transparency);  | 
        ||
| 1458 | d3dmaterial.Power = material->shininess;  | 
        ||
| 1459 | d3ddev->SetMaterial (&d3dmaterial);  | 
        ||
| 1460 | |||
| 1461 | d3ddev->SetTexture (0, textures[theme->shadow_textureindex].texture); // select the texture we want  | 
        ||
| 1462 | |||
| 1463 |    // and then draw it | 
        ||
| 1464 | d3ddev->SetStreamSource (0, tile_mesh->d3dvertices, 0, sizeof (vertex_t)); // set stream source  | 
        ||
| 1465 | d3ddev->SetFVF (tile_mesh->vertex_format); // select which vertex format we are using  | 
        ||
| 1466 | d3ddev->SetRenderState (D3DRS_CULLMODE, D3DCULL_CW); // draw the faces backwards  | 
        ||
| 1467 | if (tile_mesh->is_indexed)  | 
        ||
| 1468 |    { | 
        ||
| 1469 | d3ddev->SetIndices (tile_mesh->d3dindices);  | 
        ||
| 1470 | d3ddev->DrawIndexedPrimitive (D3DPT_TRIANGLELIST, 0, 0, tile_mesh->vertice_count, 0, tile_mesh->indice_count / 3);  | 
        ||
| 1471 |    } | 
        ||
| 1472 |    else | 
        ||
| 1473 | d3ddev->DrawPrimitive (D3DPT_TRIANGLELIST, 0, tile_mesh->vertice_count / 3);  | 
        ||
| 1474 | |||
| 1475 |    // finished, reset ambient light to its previous value and enable the Z buffer back | 
        ||
| 1476 | d3ddev->SetRenderState (D3DRS_AMBIENT, ambient_light);  | 
        ||
| 1477 | d3ddev->SetRenderState (D3DRS_ZENABLE, true);  | 
        ||
| 1478 | |||
| 1479 | return; // finished  | 
        ||
| 1480 | } | 
        ||
| 1481 | |||
| 1482 | |||
| 1483 | static void Render_DrawSceneObject (sceneobject_t *sceneobject)  | 
        ||
| 1484 | { | 
        ||
| 1485 |    // fast helper to draw a mesh at a specified location with certain pitch and yaw angles | 
        ||
| 1486 | |||
| 1487 |    D3DXMATRIX rotation_matrix; | 
        ||
| 1488 |    D3DXMATRIX translation_matrix; | 
        ||
| 1489 |    D3DXMATRIX scaling_matrix; | 
        ||
| 1490 | material_t *material;  | 
        ||
| 1491 |    D3DMATERIAL9 d3dmaterial; | 
        ||
| 1492 | mesh_t *mesh;  | 
        ||
| 1493 | |||
| 1494 |    // is this object a tile (i.e, it has no mesh) ? | 
        ||
| 1495 | if (sceneobject->mesh_index == -1)  | 
        ||
| 1496 |    { | 
        ||
| 1497 | Render_DrawSceneTile (sceneobject); // then draw it as a tile instead  | 
        ||
| 1498 | return; // and return  | 
        ||
| 1499 |    } | 
        ||
| 1500 | |||
| 1501 |    // quick access to mesh | 
        ||
| 1502 | mesh = &meshes[sceneobject->mesh_index];  | 
        ||
| 1503 | |||
| 1504 |    // set the world transform at location | 
        ||
| 1505 | D3DXMatrixRotationYawPitchRoll (&rotation_matrix, sceneobject->pitch * TO_RADIANS, 0.0f, sceneobject->yaw * TO_RADIANS);  | 
        ||
| 1506 | D3DXMatrixTranslation (&translation_matrix, sceneobject->x, sceneobject->y, sceneobject->z);  | 
        ||
| 1507 | D3DXMatrixScaling (&scaling_matrix, sceneobject->scale, sceneobject->scale, 1.0f);  | 
        ||
| 1508 | |||
| 1509 |    // tell Direct3D about our matrix | 
        ||
| 1510 | d3ddev->SetTransform (D3DTS_WORLD, &(scaling_matrix * rotation_matrix * translation_matrix));  | 
        ||
| 1511 | |||
| 1512 |    // set the texture for this mesh | 
        ||
| 1513 | if (sceneobject->texture_index != -1)  | 
        ||
| 1514 | d3ddev->SetTexture (0, textures[sceneobject->texture_index].texture);  | 
        ||
| 1515 |    else | 
        ||
| 1516 | d3ddev->SetTexture (0, NULL);  | 
        ||
| 1517 | |||
| 1518 |    // adjust the light reflection properties by setting the material | 
        ||
| 1519 | if (sceneobject->material_index != -1)  | 
        ||
| 1520 | material = &materials[sceneobject->material_index];  | 
        ||
| 1521 |    else | 
        ||
| 1522 | material = &materials[material_count - 1];  | 
        ||
| 1523 | d3dmaterial.Ambient = D3DXCOLOR (material->ambient, material->ambient, material->ambient, material->transparency);  | 
        ||
| 1524 | d3dmaterial.Diffuse = D3DXCOLOR (material->diffuse, material->diffuse, material->diffuse, material->transparency);  | 
        ||
| 1525 | d3dmaterial.Emissive = D3DXCOLOR (material->emissive, material->emissive, material->emissive, material->transparency);  | 
        ||
| 1526 | d3dmaterial.Specular = D3DXCOLOR (material->specular, material->specular, material->specular, material->transparency);  | 
        ||
| 1527 | d3dmaterial.Power = material->shininess;  | 
        ||
| 1528 | d3ddev->SetMaterial (&d3dmaterial);  | 
        ||
| 1529 | |||
| 1530 |    // draw the mesh subset | 
        ||
| 1531 | d3ddev->SetStreamSource (0, mesh->d3dvertices, 0, sizeof (vertex_t));  | 
        ||
| 1532 | d3ddev->SetFVF (mesh->vertex_format);  | 
        ||
| 1533 | |||
| 1534 |    // is there transparency on this mesh ? | 
        ||
| 1535 | if (material->transparency < 1)  | 
        ||
| 1536 |    { | 
        ||
| 1537 | d3ddev->SetRenderState (D3DRS_CULLMODE, D3DCULL_CW); // draw the back faces  | 
        ||
| 1538 | if (mesh->is_indexed)  | 
        ||
| 1539 |       { | 
        ||
| 1540 | d3ddev->SetIndices (mesh->d3dindices);  | 
        ||
| 1541 | d3ddev->DrawIndexedPrimitive (D3DPT_TRIANGLELIST, 0, 0, mesh->vertice_count, 0, mesh->indice_count / 3);  | 
        ||
| 1542 |       } | 
        ||
| 1543 |       else | 
        ||
| 1544 | d3ddev->DrawPrimitive (D3DPT_TRIANGLELIST, 0, mesh->vertice_count / 3);  | 
        ||
| 1545 |    } | 
        ||
| 1546 | |||
| 1547 |    // now draw the front faces | 
        ||
| 1548 | d3ddev->SetRenderState (D3DRS_CULLMODE, D3DCULL_CCW); // draw the front faces  | 
        ||
| 1549 | if (mesh->is_indexed)  | 
        ||
| 1550 |    { | 
        ||
| 1551 | d3ddev->SetIndices (mesh->d3dindices);  | 
        ||
| 1552 | d3ddev->DrawIndexedPrimitive (D3DPT_TRIANGLELIST, 0, 0, mesh->vertice_count, 0, mesh->indice_count / 3);  | 
        ||
| 1553 |    } | 
        ||
| 1554 |    else | 
        ||
| 1555 | d3ddev->DrawPrimitive (D3DPT_TRIANGLELIST, 0, mesh->vertice_count / 3);  | 
        ||
| 1556 | |||
| 1557 | return; // finished  | 
        ||
| 1558 | } | 
        ||
| 1559 | |||
| 1560 | |||
| 1561 | static void Render_DrawSceneTile (sceneobject_t *sceneobject)  | 
        ||
| 1562 | { | 
        ||
| 1563 |    // fast helper to draw a tile (i.e, an object that doesn't have a mesh) at a specified location | 
        ||
| 1564 | |||
| 1565 |    D3DXMATRIX rotation_matrix; | 
        ||
| 1566 |    D3DXMATRIX translation_matrix; | 
        ||
| 1567 |    D3DXMATRIX scaling_matrix; | 
        ||
| 1568 | material_t *material;  | 
        ||
| 1569 |    D3DMATERIAL9 d3dmaterial; | 
        ||
| 1570 | mesh_t *tile_mesh;  | 
        ||
| 1571 | |||
| 1572 | tile_mesh = &meshes[theme->tile_meshindex]; // quick access to tile mesh  | 
        ||
| 1573 | |||
| 1574 |    // grab the tools we need in hand | 
        ||
| 1575 | d3ddev->SetRenderState (D3DRS_AMBIENT, D3DCOLOR_RGBA (0xFF, 0xFF, 0xFF, 0xFF)); // raise light  | 
        ||
| 1576 | |||
| 1577 |    // set the world transform at location | 
        ||
| 1578 | D3DXMatrixRotationYawPitchRoll (&rotation_matrix, sceneobject->pitch * TO_RADIANS, 0.0f, sceneobject->yaw * TO_RADIANS);  | 
        ||
| 1579 | D3DXMatrixTranslation (&translation_matrix, sceneobject->x, sceneobject->y, sceneobject->z);  | 
        ||
| 1580 | D3DXMatrixScaling (&scaling_matrix, sceneobject->scale, sceneobject->scale, 1.0f);  | 
        ||
| 1581 | |||
| 1582 |    // tell Direct3D about our matrix | 
        ||
| 1583 | d3ddev->SetTransform (D3DTS_WORLD, &(scaling_matrix * rotation_matrix * translation_matrix));  | 
        ||
| 1584 | |||
| 1585 |    // adjust the light reflection properties by setting the material | 
        ||
| 1586 | material = &materials[material_count - 1]; // use the default material for tiles  | 
        ||
| 1587 | d3dmaterial.Ambient = D3DXCOLOR (material->ambient, material->ambient, material->ambient, material->ambient);  | 
        ||
| 1588 | d3dmaterial.Diffuse = D3DXCOLOR (material->diffuse, material->diffuse, material->diffuse, material->diffuse);  | 
        ||
| 1589 | d3dmaterial.Emissive = D3DXCOLOR (material->emissive, material->emissive, material->emissive, material->emissive);  | 
        ||
| 1590 | d3dmaterial.Specular = D3DXCOLOR (material->specular, material->specular, material->specular, material->specular);  | 
        ||
| 1591 | d3dmaterial.Power = material->shininess;  | 
        ||
| 1592 | d3ddev->SetMaterial (&d3dmaterial);  | 
        ||
| 1593 | |||
| 1594 |    // select the texture we want | 
        ||
| 1595 | d3ddev->SetTexture (0, textures[sceneobject->texture_index].texture);  | 
        ||
| 1596 | |||
| 1597 |    // and then draw it | 
        ||
| 1598 | d3ddev->SetStreamSource (0, tile_mesh->d3dvertices, 0, sizeof (vertex_t)); // set stream source  | 
        ||
| 1599 | d3ddev->SetFVF (tile_mesh->vertex_format); // select which vertex format we are using  | 
        ||
| 1600 | d3ddev->SetRenderState (D3DRS_CULLMODE, D3DCULL_CW); // draw the back faces  | 
        ||
| 1601 | if (tile_mesh->is_indexed)  | 
        ||
| 1602 |    { | 
        ||
| 1603 | d3ddev->SetIndices (tile_mesh->d3dindices);  | 
        ||
| 1604 | d3ddev->DrawIndexedPrimitive (D3DPT_TRIANGLELIST, 0, 0, tile_mesh->vertice_count, 0, tile_mesh->indice_count / 3);  | 
        ||
| 1605 |    } | 
        ||
| 1606 |    else | 
        ||
| 1607 | d3ddev->DrawPrimitive (D3DPT_TRIANGLELIST, 0, tile_mesh->vertice_count / 3);  | 
        ||
| 1608 | |||
| 1609 |    // finished, reset ambient light to its previous value | 
        ||
| 1610 | d3ddev->SetRenderState (D3DRS_AMBIENT, ambient_light);  | 
        ||
| 1611 | |||
| 1612 | return; // finished  | 
        ||
| 1613 | } | 
        ||
| 1614 | |||
| 1615 | |||
| 1616 | static void Render_DrawSprite (sprite_t *sprite, float x_percent, float y_percent, float width_percent, float height_percent, int alpha)  | 
        ||
| 1617 | { | 
        ||
| 1618 |    // fast helper to draw a sprite at a specified location with certain parameters | 
        ||
| 1619 | |||
| 1620 |    D3DXMATRIX scaling_matrix; | 
        ||
| 1621 | texture_t *texture;  | 
        ||
| 1622 | float scale_x;  | 
        ||
| 1623 | float scale_y;  | 
        ||
| 1624 | |||
| 1625 | texture = &textures[sprite->texture_index]; // quick access to sprite's texture  | 
        ||
| 1626 | |||
| 1627 | scale_x = (width_percent * (float) initial_width) / (float) (100 * texture->width);  | 
        ||
| 1628 | scale_y = (height_percent * (float) initial_height) / (float) (100 * texture->height);  | 
        ||
| 1629 | |||
| 1630 |    // start rendering the sprite (an optimized version would draw all sprites in a row...) | 
        ||
| 1631 | sprite->sprite->Begin (D3DXSPRITE_ALPHABLEND);  | 
        ||
| 1632 | |||
| 1633 |    // scale and position the sprite | 
        ||
| 1634 | D3DXMatrixTransformation2D (&scaling_matrix, // output matrix  | 
        ||
| 1635 | NULL, // scaling center  | 
        ||
| 1636 | 0.0f, // scaling rotation  | 
        ||
| 1637 | &D3DXVECTOR2 (scale_x, scale_y), // scaling ratio  | 
        ||
| 1638 | &D3DXVECTOR2 (0, 0), // rotation center  | 
        ||
| 1639 | 0.0f, // rotation  | 
        ||
| 1640 | &D3DXVECTOR2 (x_percent * (float) initial_width / 100.0f, y_percent * (float) initial_height / 100.0f)); // translation  | 
        ||
| 1641 | sprite->sprite->SetTransform (&scaling_matrix); // tell the sprite about the scaling and position transform  | 
        ||
| 1642 | |||
| 1643 |    // now draw the sprite with the specified alpha and finish rendering | 
        ||
| 1644 | sprite->sprite->Draw (texture->texture, NULL, NULL, NULL, D3DCOLOR_ARGB (alpha, 255, 255, 255));  | 
        ||
| 1645 | sprite->sprite->End ();  | 
        ||
| 1646 | |||
| 1647 | return; // finished  | 
        ||
| 1648 | } | 
        ||
| 1649 | |||
| 1650 | |||
| 124 | pmbaty | 1651 | static void Render_GetTextBoundaries (float maxwidth_percent, int font_id, wchar_t *text, RECT *rect)  | 
        
| 1 | pmbaty | 1652 | { | 
        
| 1653 |    // this function computes and returns the size of the rectangle the specified text will fit into. Note that text may be modified | 
        ||
| 1654 |    // to insert new lines if it doesn't fit in a single line. | 
        ||
| 1655 | |||
| 1656 | int char_index;  | 
        ||
| 1657 | int length;  | 
        ||
| 1658 | int optimal_length;  | 
        ||
| 1659 | bool have_split;  | 
        ||
| 124 | pmbaty | 1660 | int max_width;  | 
        
| 1 | pmbaty | 1661 | |
| 1662 |    // blank out the output rectangle | 
        ||
| 1663 | memset (rect, 0, sizeof (RECT));  | 
        ||
| 1664 | |||
| 1665 |    // ask direct3D to compute the text size a first time | 
        ||
| 1666 | fonts[font_id].font->DrawText (NULL, text, -1, rect, DT_CALCRECT, D3DCOLOR (0));  | 
        ||
| 1667 | |||
| 1668 |    // if max width is not set, set it to viewport width | 
        ||
| 124 | pmbaty | 1669 | if (maxwidth_percent <= 0)  | 
        
| 1 | pmbaty | 1670 | max_width = initial_width; // then use it to compute the real max width  | 
        
| 124 | pmbaty | 1671 |    else | 
        
| 1672 | max_width = (int) ((maxwidth_percent * (float) initial_width) / 100.0f); // else if specified, convert this percentage to an absolute pixel width  | 
        ||
| 1 | pmbaty | 1673 | |
| 1674 |    // do we need more than one line ? | 
        ||
| 1675 | if (rect->right > max_width)  | 
        ||
| 1676 |    { | 
        ||
| 1677 |       // see how many lines we need and compute the optimal length of one line | 
        ||
| 1678 | length = wcslen (text);  | 
        ||
| 1679 | optimal_length = length / (1 + rect->right / (int) max_width);  | 
        ||
| 1680 | have_split = false;  | 
        ||
| 1681 | for (char_index = optimal_length; char_index < length; char_index++)  | 
        ||
| 1682 | if (iswspace (text[char_index]))  | 
        ||
| 1683 |          { | 
        ||
| 1684 | text[char_index] = L'\n'; // interpolate linefeeds into string  | 
        ||
| 1685 | have_split = true; // remember string has been split  | 
        ||
| 1686 | char_index += optimal_length;  | 
        ||
| 1687 |          } | 
        ||
| 1688 | |||
| 1689 |       // and ask direct3D to compute the text size again | 
        ||
| 1690 | fonts[font_id].font->DrawText (NULL, text, -1, rect, DT_CALCRECT, D3DCOLOR (0));  | 
        ||
| 1691 |    } | 
        ||
| 1692 | |||
| 1693 | return; // finished  | 
        ||
| 1694 | } | 
        ||
| 1695 | |||
| 1696 | |||
| 124 | pmbaty | 1697 | static void Render_wprintf (float x_percent, float y_percent, float maxwidth_percent, int horiz_align, int vert_align, int text_align, int font_id, unsigned long color_rgba, RECT *out_rect, const wchar_t *fmt, ...)  | 
        
| 1 | pmbaty | 1698 | { | 
        
| 1699 |    // this function displays text on the Direct3D interface according to the given parameters. X and Y are the base coordinates of | 
        ||
| 1700 |    // the text's bounding rectangle. Max_width is the maximum allowed width of this rectangle before wrapping words on a new line. | 
        ||
| 1701 |    // Horiz_align and vert_align are the alignment parameters of the RECTANGLE relatively to X and Y. Text_align is the alignment of | 
        ||
| 1702 |    // the TEXT inside this rectangle (meaning, you can have right-aligned text in a rectangle that is centered on a point). Font_id | 
        ||
| 1703 |    // and color.alphargb define the font and color of the text. Out_rect, if filled, will point to a RECT structure describing the text's | 
        ||
| 1704 |    // bounding rectangle, after any word wrapping corrections have been made. Fmt is a format string containing the text itself, | 
        ||
| 1705 |    // printf-style. | 
        ||
| 1706 | |||
| 1707 | va_list argptr;  | 
        ||
| 1708 |    RECT rect; | 
        ||
| 1709 | int left;  | 
        ||
| 1710 | int top;  | 
        ||
| 124 | pmbaty | 1711 | int x;  | 
        
| 1712 | int y;  | 
        ||
| 1 | pmbaty | 1713 | |
| 1714 |    // concatenate all the arguments in one string | 
        ||
| 1715 | va_start (argptr, fmt);  | 
        ||
| 1716 | wvsprintf (printf_buffer, fmt, argptr);  | 
        ||
| 1717 | va_end (argptr);  | 
        ||
| 1718 | |||
| 124 | pmbaty | 1719 |    // translate percent coordinates into absolute coordinates | 
        
| 1720 | x = (int) ((x_percent * (float) initial_width) / 100.0f);  | 
        ||
| 1721 | y = (int) ((y_percent * (float) initial_height) / 100.0f);  | 
        ||
| 1722 | |||
| 1 | pmbaty | 1723 |    // get the text boundaries | 
        
| 124 | pmbaty | 1724 | Render_GetTextBoundaries (maxwidth_percent, font_id, printf_buffer, &rect);  | 
        
| 1 | pmbaty | 1725 | |
| 1726 |    // horizontal alignment | 
        ||
| 1727 | if (horiz_align == ALIGN_LEFT)  | 
        ||
| 1728 | left = x;  | 
        ||
| 1729 | else if (horiz_align == ALIGN_RIGHT)  | 
        ||
| 1730 | left = x - rect.right;  | 
        ||
| 1731 |    else | 
        ||
| 1732 | left = x - rect.right / 2;  | 
        ||
| 1733 | |||
| 1734 |    // vertical alignment | 
        ||
| 1735 | if (vert_align == ALIGN_TOP)  | 
        ||
| 1736 | top = y;  | 
        ||
| 1737 | else if (vert_align == ALIGN_BOTTOM)  | 
        ||
| 1738 | top = y - rect.bottom;  | 
        ||
| 1739 |    else | 
        ||
| 1740 | top = y - rect.bottom / 2;  | 
        ||
| 1741 | |||
| 1742 |    // now reposition our rectangle correctly acording to alignment | 
        ||
| 1743 | OffsetRect (&rect, left, top);  | 
        ||
| 1744 | |||
| 1745 |    // and draw the text | 
        ||
| 1746 | if (text_align == ALIGN_LEFT)  | 
        ||
| 1747 | fonts[font_id].font->DrawText (NULL, printf_buffer, -1, &rect, DT_LEFT, RGBACOLOR_TO_ARGBCOLOR (color_rgba));  | 
        ||
| 1748 | else if (horiz_align == ALIGN_RIGHT)  | 
        ||
| 1749 | fonts[font_id].font->DrawText (NULL, printf_buffer, -1, &rect, DT_RIGHT, RGBACOLOR_TO_ARGBCOLOR (color_rgba));  | 
        ||
| 1750 |    else | 
        ||
| 1751 | fonts[font_id].font->DrawText (NULL, printf_buffer, -1, &rect, DT_CENTER, RGBACOLOR_TO_ARGBCOLOR (color_rgba));  | 
        ||
| 1752 | |||
| 1753 |    // do we want the output rectangle ? | 
        ||
| 1754 | if (out_rect != NULL)  | 
        ||
| 1755 | memcpy (out_rect, &rect, sizeof (rect)); // if so, copy it in the given variable  | 
        ||
| 1756 | |||
| 1757 | return; // finished  | 
        ||
| 1758 | } | 
        ||
| 1759 | |||
| 1760 | |||
| 1761 | static float DistanceToCamera (float x, float y, float z)  | 
        ||
| 1762 | { | 
        ||
| 1763 |    // this function computes the distance of the point at coordinates x,y,z to the camera | 
        ||
| 1764 | |||
| 1765 |    vector_t displacement; | 
        ||
| 1766 | |||
| 1767 |    // compute displacement... | 
        ||
| 1768 | displacement.x = x - camera_position.x;  | 
        ||
| 1769 | displacement.y = y - camera_position.y;  | 
        ||
| 1770 | displacement.z = z - camera_position.z;  | 
        ||
| 1771 | |||
| 1772 |    // ...and then Pythagores in 3D | 
        ||
| 1773 | return (sqrtf (displacement.x * displacement.x + displacement.y * displacement.y + displacement.z * displacement.z));  | 
        ||
| 1774 | } | 
        ||
| 1775 | |||
| 1776 | |||
| 1777 | static float FadeFloat (float from, float to, float start_time, float end_time)  | 
        ||
| 1778 | { | 
        ||
| 1779 |    // helper function to return a progressive variation between from and to based on time | 
        ||
| 1780 | |||
| 1781 | if (end_time < current_time)  | 
        ||
| 1782 | return (to);  | 
        ||
| 1783 | |||
| 1784 |    //      base + (variation) * (               fraction of completion               ) | 
        ||
| 1785 | return (from + (to - from) * (current_time - start_time) / (end_time - start_time));  | 
        ||
| 1786 | } | 
        ||
| 1787 | |||
| 1788 | |||
| 1789 | static unsigned long HashString (const wchar_t *string_buffer)  | 
        ||
| 1790 | { | 
        ||
| 1791 |    // super fast string hash function, code courtesy of | 
        ||
| 1792 |    // http://www.azillionmonkeys.com/qed/hash.html | 
        ||
| 1793 | |||
| 1794 | unsigned long length;  | 
        ||
| 1795 | unsigned long hash;  | 
        ||
| 1796 | unsigned long tmp;  | 
        ||
| 1797 | int remaining;  | 
        ||
| 1798 | |||
| 1799 |    // first, get the string length and start with this as a hash value | 
        ||
| 1800 | length = wcslen (string_buffer) * sizeof (wchar_t);  | 
        ||
| 1801 | hash = length;  | 
        ||
| 1802 | |||
| 1803 |    // figure out how many bytes there will remain after 32-bit processing | 
        ||
| 1804 | remaining = length & 3;  | 
        ||
| 1805 | length >>= 2;  | 
        ||
| 1806 | |||
| 1807 |    // main loop, process 32-bit blocks | 
        ||
| 1808 | for ( ; length > 0; length--)  | 
        ||
| 1809 |    { | 
        ||
| 1810 | hash += *((const unsigned short *) string_buffer);  | 
        ||
| 1811 | tmp = ((*((const unsigned short *) (string_buffer + 2))) << 11) ^ hash;  | 
        ||
| 1812 | hash = (hash << 16) ^ tmp;  | 
        ||
| 1813 | string_buffer += 2 * sizeof (unsigned short);  | 
        ||
| 1814 | hash += hash >> 11;  | 
        ||
| 1815 |    } | 
        ||
| 1816 | |||
| 1817 |    // handle the remaining bytes | 
        ||
| 1818 | if (remaining == 3)  | 
        ||
| 1819 |    { | 
        ||
| 1820 | hash += *((const unsigned short *) string_buffer);  | 
        ||
| 1821 | hash ^= hash << 16;  | 
        ||
| 1822 | hash ^= string_buffer[sizeof (unsigned short)] << 18;  | 
        ||
| 1823 | hash += hash >> 11;  | 
        ||
| 1824 |    } | 
        ||
| 1825 | else if (remaining == 2)  | 
        ||
| 1826 |    { | 
        ||
| 1827 | hash += *((const unsigned short *) string_buffer);  | 
        ||
| 1828 | hash ^= hash << 11;  | 
        ||
| 1829 | hash += hash >> 17;  | 
        ||
| 1830 |    } | 
        ||
| 1831 | else if (remaining == 1)  | 
        ||
| 1832 |    { | 
        ||
| 1833 | hash += *string_buffer;  | 
        ||
| 1834 | hash ^= hash << 10;  | 
        ||
| 1835 | hash += hash >> 1;  | 
        ||
| 1836 |    } | 
        ||
| 1837 | |||
| 1838 |    // force "avalanching" of final 127 bits | 
        ||
| 1839 | hash ^= hash << 3;  | 
        ||
| 1840 | hash += hash >> 5;  | 
        ||
| 1841 | hash ^= hash << 4;  | 
        ||
| 1842 | hash += hash >> 17;  | 
        ||
| 1843 | hash ^= hash << 25;  | 
        ||
| 1844 | hash += hash >> 6;  | 
        ||
| 1845 | |||
| 1846 | return (hash); // finished, return the hash value  | 
        ||
| 1847 | } | 
        ||
| 1848 | |||
| 1849 | |||
| 1850 | static unsigned long HashFile (const wchar_t *file_pathname)  | 
        ||
| 1851 | { | 
        ||
| 1852 |    // super fast file content pseudo-hash function | 
        ||
| 1853 | |||
| 1854 | unsigned short value;  | 
        ||
| 81 | pmbaty | 1855 | unsigned long file_size;  | 
        
| 1 | pmbaty | 1856 | FILE *fp;  | 
        
| 1857 | |||
| 1858 |    // open the file | 
        ||
| 1859 | _wfopen_s (&fp, file_pathname, L"rb");  | 
        ||
| 1860 | if (fp == NULL)  | 
        ||
| 1861 | return ((unsigned long) time (NULL)); // if file can't be open, return a random number  | 
        ||
| 1862 | |||
| 81 | pmbaty | 1863 |    // seek at end of file, read file size, and rewind | 
        
| 1864 | fseek (fp, 0, SEEK_END);  | 
        ||
| 1865 | file_size = ftell (fp);  | 
        ||
| 1866 | fseek (fp, 0, SEEK_SET);  | 
        ||
| 1867 | |||
| 1 | pmbaty | 1868 |    // seek at 2/3 of file size (if file is small enough, return only its content) | 
        
| 81 | pmbaty | 1869 | if (file_size >= 4)  | 
        
| 1 | pmbaty | 1870 |    { | 
        
| 81 | pmbaty | 1871 | fseek (fp, file_size * 2 / 3, SEEK_SET); // seek at 2/3 of file  | 
        
| 1 | pmbaty | 1872 | fread (&value, 2, 1, fp); // and read a word here  | 
        
| 1873 |    } | 
        ||
| 81 | pmbaty | 1874 | else if (file_size >= 2)  | 
        
| 1 | pmbaty | 1875 | fread (&value, 2, 1, fp);  | 
        
| 81 | pmbaty | 1876 | else if (file_size == 1)  | 
        
| 1 | pmbaty | 1877 | value = fgetc (fp);  | 
        
| 1878 |    else | 
        ||
| 1879 | value = 0;  | 
        ||
| 1880 | |||
| 1881 |    // finished, close the file | 
        ||
| 1882 | fclose (fp);  | 
        ||
| 1883 | |||
| 1884 |    // and return a hash composed of the 16 lower bits of the file size and the value we read | 
        ||
| 81 | pmbaty | 1885 | return ((unsigned long) (file_size << 16) | (unsigned long) value);  | 
        
| 1 | pmbaty | 1886 | } | 
        
| 1887 | |||
| 1888 | |||
| 1889 | static void ResolveWildcard (wchar_t *file_pathname, wchar_t *extensions_separated_by_bars)  | 
        ||
| 1890 | { | 
        ||
| 1891 |    // this function resolves a pathname ending with .* by testing with various possible | 
        ||
| 1892 |    // file extensions until one of the files formed that way is found to exist. | 
        ||
| 1893 | |||
| 1894 | static wchar_t extension_list[256]; // needs to be modifiable for strtok()  | 
        ||
| 1895 | wchar_t *current_extension;  | 
        ||
| 1896 | wchar_t *wcstok_context;  | 
        ||
| 1897 | int length;  | 
        ||
| 1898 | |||
| 1899 | wcscpy_s (extension_list, WCHAR_SIZEOF (extension_list), extensions_separated_by_bars);  | 
        ||
| 1900 | length = wcslen (file_pathname); // get pathname length  | 
        ||
| 1901 | |||
| 1902 |    // does the pathname we want NOT end with a wildcard ? | 
        ||
| 1903 | if ((length < 2) || (wcscmp (&file_pathname[length - 2], L".*") != 0))  | 
        ||
| 1904 | return; // no need to resolve anything  | 
        ||
| 1905 | |||
| 1906 |    // test each extension and see if a corresponding file exists | 
        ||
| 1907 | current_extension = wcstok_s (extension_list, L"|", &wcstok_context);  | 
        ||
| 1908 | while (current_extension != NULL)  | 
        ||
| 1909 |    { | 
        ||
| 1910 | if (*current_extension == L'.')  | 
        ||
| 1911 | current_extension++; // if current extension starts with a dot, skip it  | 
        ||
| 81 | pmbaty | 1912 | |
| 1 | pmbaty | 1913 | wcscpy_s (&file_pathname[length - 1], wcslen (current_extension) + 1, current_extension);  | 
        
| 81 | pmbaty | 1914 | if (_waccess (file_pathname, 0) == 0)  | 
        
| 1 | pmbaty | 1915 | return; // found a file with this extension  | 
        
| 1916 | current_extension = wcstok_s (NULL, L"|", &wcstok_context);  | 
        ||
| 1917 |    } | 
        ||
| 1918 | |||
| 1919 | wcscpy_s (&file_pathname[length - 1], 2, L"*");  | 
        ||
| 1920 | return; // if none of these extensions match, put the wildcard back and return  | 
        ||
| 1921 | } | 
        ||
| 1922 | |||
| 1923 | |||
| 1924 | static int SortReflectedObjects (const void *object1, const void *object2)  | 
        ||
| 1925 | { | 
        ||
| 1926 |    // callback function used by qsort() when sorting the reflected objects according to their distance to the viewer | 
        ||
| 1927 | |||
| 1928 | return ((int) (1000.0f * (((reflectedobject_t *) object2)->distance - ((reflectedobject_t *) object1)->distance)));  | 
        ||
| 1929 | } |