MuckyFoot-UrbanChaos/fallen/outro/os.cpp
2017-05-20 11:14:17 +10:00

4086 lines
72 KiB
C++

#include <windows.h>
#include <windowsx.h>
#include <ddraw.h>
#include <d3d.h>
#include <d3dtypes.h>
// For the DX8 headers, you need to define this to get old interfaces.
#ifndef DIRECTINPUT_VERSION
#define DIRECTINPUT_VERSION 0x0700
#endif
#include <dinput.h>
#include <stdarg.h>
#include <string.h>
#include "always.h"
#include "key.h"
#include "os.h"
#include "matrix.h"
#include "tga.h"
#include "c:\fallen\ddlibrary\headers\ddlib.h"
#include "c:\fallen\ddlibrary\headers\mfx.h"
#include "c:\fallen\headers\music.h"
#include "c:\fallen\headers\sound_id.h"
//#include "midasdll.h"
//
// The entrypoint into the actual game.
//
extern void MAIN_main(void);
HINSTANCE OS_this_instance;
HINSTANCE OS_last_instance;
LPSTR OS_command_line;
int OS_start_show_state;
CBYTE *OS_application_name = "Urban Chaos credits";
//
// Our window class.
//
WNDCLASSEX OS_wcl;
//
// Our window handle.
//
HWND OS_window_handle;
//
// The DirectX 6 framework library class.
//
UBYTE OS_frame_is_fullscreen;
UBYTE OS_frame_is_hardware;
typedef class
{
public:
LPDIRECTDRAW4 direct_draw;
LPDIRECT3DDEVICE3 direct_3d;
LPDIRECTDRAW4 GetDirectDraw() { return direct_draw; }
LPDIRECT3DDEVICE3 GetD3DDevice() { return direct_3d; }
} OS_Framework;
OS_Framework OS_frame;
// ========================================================
//
// THE SCREEN
//
// ========================================================
float OS_screen_width;
float OS_screen_height;
// ========================================================
//
// KEY HANDLING STUFF
//
// ========================================================
//
// The keys that are held down.
//
UBYTE KEY_on[256];
UBYTE KEY_inkey;
UBYTE KEY_shift;
// ========================================================
//
// MIDAS STUFF
//
// ========================================================
SLONG OS_midas_ok;
//MIDASmodule OS_module;
//MIDASmodulePlayHandle OS_module_handle;
// ========================================================
//
// JOYSTICK STUFF
//
// ========================================================
IDirectInput *OS_joy_direct_input;
IDirectInputDevice *OS_joy_input_device;
IDirectInputDevice2 *OS_joy_input_device2; // We need this newer interface to poll the joystick.
float OS_joy_x;
float OS_joy_y;
SLONG OS_joy_x_range_min;
SLONG OS_joy_x_range_max;
SLONG OS_joy_y_range_min;
SLONG OS_joy_y_range_max;
ULONG OS_joy_button; // The buttons that are currently down
ULONG OS_joy_button_down; // The buttons that have just been pressed
ULONG OS_joy_button_up; // The buttons that have just been released
//
// The callback function for enumerating joysticks.
//
BOOL CALLBACK OS_joy_enum(
LPCDIDEVICEINSTANCE instance,
LPVOID context )
{
HRESULT hr;
LPDIRECTINPUTDEVICE pDevice;
//
// Get an interface to the joystick.
//
hr = OS_joy_direct_input->CreateDevice(
instance->guidInstance,
&OS_joy_input_device,
NULL);
if (FAILED(hr))
{
//
// Cant use this joystick for some reason!
//
OS_joy_input_device = NULL;
OS_joy_input_device2 = NULL;
return DIENUM_CONTINUE;
}
//
// Query for the IDirectInputDevice2 interface.
// We need this to poll the joystick.
//
OS_joy_input_device->QueryInterface(
IID_IDirectInputDevice2,
(LPVOID *) &OS_joy_input_device2);
//
// No need to find another joystick!
//
return DIENUM_STOP;
}
//
// Initialises the joystick.
//
void OS_joy_init(void)
{
HRESULT hr;
//
// Initialise everything.
//
OS_joy_direct_input = NULL;
OS_joy_input_device = NULL;
OS_joy_input_device2 = NULL;
//
// Create the direct input object.
//
hr = DirectInputCreate(
OS_this_instance,
DIRECTINPUT_VERSION,
&OS_joy_direct_input,
NULL);
if (FAILED(hr))
{
//
// No direct input!
//
return;
}
//
// Find a joystick.
//
hr = OS_joy_direct_input->EnumDevices(
DIDEVTYPE_JOYSTICK,
OS_joy_enum,
NULL,
DIEDFL_ATTACHEDONLY);
if (OS_joy_input_device == NULL ||
OS_joy_input_device2 == NULL)
{
//
// The joystick wasn't properly found.
//
OS_joy_input_device = NULL;
OS_joy_input_device2 = NULL;
return;
}
//
// So we can get the nice 'n' simple joystick data format.
//
OS_joy_input_device->SetDataFormat(&c_dfDIJoystick);
//
// Grab the joystick exclusively when our window in the foreground.
//
OS_joy_input_device->SetCooperativeLevel(
OS_window_handle,
DISCL_EXCLUSIVE | DISCL_FOREGROUND);
//
// What is the range of the joystick?
//
DIPROPRANGE diprg;
//
// In x...
//
diprg.diph.dwSize = sizeof(DIPROPRANGE);
diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
diprg.diph.dwHow = DIPH_BYOFFSET;
diprg.diph.dwObj = DIJOFS_X;
diprg.lMin = 0;
diprg.lMax = 0;
OS_joy_input_device->GetProperty(
DIPROP_RANGE,
&diprg.diph);
OS_joy_x_range_min = diprg.lMin;
OS_joy_x_range_max = diprg.lMax;
//
// In y...
//
diprg.diph.dwSize = sizeof(DIPROPRANGE);
diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
diprg.diph.dwHow = DIPH_BYOFFSET;
diprg.diph.dwObj = DIJOFS_Y;
diprg.lMin = 0;
diprg.lMax = 0;
OS_joy_input_device->GetProperty(
DIPROP_RANGE,
&diprg.diph);
OS_joy_y_range_min = diprg.lMin;
OS_joy_y_range_max = diprg.lMax;
}
//
// Polls the joystick.
//
void OS_joy_poll(void)
{
HRESULT hr;
if (OS_joy_direct_input == NULL ||
OS_joy_input_device == NULL ||
OS_joy_input_device2 == NULL)
{
//
// No joystick detected.
//
OS_joy_x = 0.0F;
OS_joy_y = 0.0F;
OS_joy_button = 0;
OS_joy_button_down = 0;
OS_joy_button_up = 0;
return;
}
//
// Acquire the joystick.
//
hr = OS_joy_input_device->Acquire();
if (hr == DI_OK)
{
DIJOYSTATE js;
//
// We acquired the joystick okay. Poll the joystick to
// update its state.
//
OS_joy_input_device2->Poll();
//
// Finally get the state of the joystick.
//
hr = OS_joy_input_device ->GetDeviceState(sizeof(js), &js);
if (!FAILED(hr))
{
//
// Axis movment normalised to between -1.0F and +1.0F
//
SLONG dx = OS_joy_x_range_max - OS_joy_x_range_min;
SLONG dy = OS_joy_y_range_max - OS_joy_y_range_min;
OS_joy_x = 0.0F;
OS_joy_y = 0.0F;
if (dx) {OS_joy_x = float(js.lX - OS_joy_x_range_min) * 2.0F / float(dx) - 1.0F;}
if (dy) {OS_joy_y = float(js.lY - OS_joy_y_range_min) * 2.0F / float(dy) - 1.0F;}
//
// The buttons.
//
SLONG i;
ULONG last = OS_joy_button;
ULONG now = 0;
for (i = 0; i < 32; i++)
{
if (js.rgbButtons[i] & 0x80)
{
now |= 1 << i;
}
}
OS_joy_button = now;
OS_joy_button_down = now & ~last;
OS_joy_button_up = last & ~now;
}
OS_joy_input_device->Unacquire();
}
}
// ========================================================
//
// TEXTURE STUFF
//
// ========================================================
//
// The directory where we load textures from.
//
#define OS_TEXTURE_DIR "Textures\\"
//
// The pixel formats for each of our OS_TEXTURE_FORMATs
//
typedef struct
{
SLONG valid;
DDPIXELFORMAT ddpf;
SLONG mask_r;
SLONG mask_g;
SLONG mask_b;
SLONG mask_a;
SLONG shift_r;
SLONG shift_g;
SLONG shift_b;
SLONG shift_a;
} OS_Tformat;
OS_Tformat OS_tformat[OS_TEXTURE_FORMAT_NUMBER];
//
// Our texture pages.
//
typedef struct os_texture
{
CBYTE name[_MAX_PATH];
UBYTE format;
UBYTE inverted;
UWORD size;
DDSURFACEDESC2 ddsd;
LPDIRECTDRAWSURFACE4 ddsurface;
LPDIRECT3DTEXTURE2 ddtx;
OS_Texture *next;
} OS_Texture;
//
// They are stored in a linked list and dynamically allocated.
//
OS_Texture *OS_texture_head;
//
// Returns the number of bits set in 'mask' with a rather cunning algorithm.
//
SLONG OS_bit_count(ULONG mask)
{
SLONG ans;
for (ans = 0; mask; mask &= mask - 1, ans += 1);
return ans;
}
//
// The texture enumeration function.
//
HRESULT CALLBACK OS_texture_enumerate_pixel_formats(
LPDDPIXELFORMAT lpddpf,
LPVOID context)
{
SLONG format;
OS_Tformat *otf = (OS_Tformat *) malloc(sizeof(OS_Tformat));
if (otf == NULL)
{
//
// Oh dear!
//
return D3DENUMRET_CANCEL;
}
//
// Is this one of the formats we are interested in?
//
if (lpddpf->dwFlags & DDPF_RGB)
{
//
// We are only interested in 16-bpp RGB modes.
//
if (lpddpf->dwRGBBitCount == 16)
{
if (lpddpf->dwFlags & DDPF_ALPHAPIXELS)
{
SLONG alphabits;
//
// Could be 1555 or 4444
//
alphabits = OS_bit_count(lpddpf->dwRGBAlphaBitMask);
if (alphabits == 1)
{
//
// Must be 1555
//
OS_tformat[OS_TEXTURE_FORMAT_1555].valid = TRUE;
OS_tformat[OS_TEXTURE_FORMAT_1555].ddpf = *lpddpf;
}
else
if (alphabits == 4)
{
//
// Must be 4444
//
OS_tformat[OS_TEXTURE_FORMAT_4444].valid = TRUE;
OS_tformat[OS_TEXTURE_FORMAT_4444].ddpf = *lpddpf;
}
}
else
{
//
// This is a good RGB pixel format.
//
OS_tformat[OS_TEXTURE_FORMAT_RGB].valid = TRUE;
OS_tformat[OS_TEXTURE_FORMAT_RGB].ddpf = *lpddpf;
}
}
}
/*
else
if (SOFTWARE && (lpddpf->dwFlags & DDPF_LUMINANCE))
{
if (lpddpf->dwFlags & DDPF_ALPHAPIXELS)
{
//
// We only want luminance- not luminance and alpha.
//
}
else
{
if (lpddpf->dwLuminanceBitCount == 8)
{
//
// This is what we want. An 8-bit luminance format.
//
OS_tformat[OS_TEXTURE_FORMAT_8].valid = TRUE;
OS_tformat[OS_TEXTURE_FORMAT_8].ddpf = *lpddpf;
}
}
}
*/
//
// Ask for another texture format.
//
return D3DENUMRET_OK;
}
//
// Given the bitmask for a colour in a pixel format, it calculates the mask and
// shift so that you can construct a pixel in pixel format given its RGB values.
// The formula is...
//
// PIXEL(r,g,b) = ((r >> mask) << shift) | ((g >> mask) << shift) | ((b >> mask) << shift);
//
// THIS ASSUMES that r,g,b are 8-bit values.
//
void OS_calculate_mask_and_shift(
ULONG bitmask,
SLONG *mask,
SLONG *shift);
#if 0
{
SLONG i;
SLONG b;
SLONG num_bits = 0;
SLONG first_bit = -1;
for (i = 0, b = 1; i < 32; i++, b <<= 1)
{
if (bitmask & b)
{
num_bits += 1;
if (first_bit == -1)
{
//
// We have found the first bit.
//
first_bit = i;
}
}
}
ASSERT(first_bit != -1 && num_bits != 0);
*mask = 8 - num_bits;
*shift = first_bit;
if (*mask < 0)
{
//
// More than 8 bits per colour component? May
// as well support it!
//
*shift -= *mask;
*mask = 0;
}
}
#endif
OS_Texture *OS_texture_create(CBYTE *fname, SLONG invert)
{
SLONG format;
OS_Texture *ot;
OS_Tformat *best_otf;
TGA_Info ti;
TGA_Pixel *data;
CBYTE fullpath[_MAX_PATH];
//
// Do we already have this texture?
//
for (ot = OS_texture_head; ot; ot = ot->next)
{
if (strcmp(fname, ot->name) == 0)
{
if (ot->inverted == invert)
{
return ot;
}
}
}
// Allocate data for the texture.
//
data = (TGA_Pixel *) malloc(256 * 256 * sizeof(TGA_Pixel));
if (data == NULL)
{
//
// Oh dear!
//
return NULL;
}
//
// The full pathname.
//
sprintf(fullpath, OS_TEXTURE_DIR"%s", fname);
//
// Try to load in the TGA.
//
ti = TGA_load(fullpath, 256, 256, data);
if (!ti.valid)
{
//
// Failed to load the tga.
//
free(data);
return NULL;
}
if (ti.width != ti.height)
{
//
// Only square textures allowed.
//
free(data);
return NULL;
}
//
// Find the best texture format.
//
if (ti.flag & TGA_FLAG_CONTAINS_ALPHA)
{
if (ti.flag & TGA_FLAG_ONE_BIT_ALPHA)
{
format = OS_TEXTURE_FORMAT_1555;
}
else
{
format = OS_TEXTURE_FORMAT_4444;
}
}
else
if (ti.flag & TGA_FLAG_GRAYSCALE)
{
if (OS_tformat[OS_TEXTURE_FORMAT_8].valid)
{
//
// This card has a luminance only texture format.
//
format = OS_TEXTURE_FORMAT_8;
}
else
{
//
// Use the RGB format as the next-best thing.
//
format = OS_TEXTURE_FORMAT_RGB;
}
}
else
{
//
// A normal RGB texture
//
format = OS_TEXTURE_FORMAT_RGB;
}
best_otf = &OS_tformat[format];
if (!best_otf->valid)
{
//
// No good texture format.
//
free(data);
return NULL;
}
//
// Create a new texture.
//
ot = (OS_Texture *) malloc(sizeof(OS_Texture));
if (ot == NULL)
{
//
// It's really not worth checking for this... but anyway!
//
free(data);
return NULL;
}
strncpy(ot->name, fname, _MAX_PATH);
ot->format = format;
ot->inverted = invert;
//
// Create a managed texture surface.
//
memset(&ot->ddsd, 0, sizeof(ot->ddsd));
ot->ddsd.dwSize = sizeof(DDSURFACEDESC2);
ot->ddsd.dwWidth = ti.width;
ot->ddsd.dwHeight = ti.height;
ot->ddsd.dwMipMapCount = 1;
#ifdef TARGET_DC
ot->ddsd.dwFlags =
DDSD_CAPS |
DDSD_HEIGHT |
DDSD_WIDTH |
DDSD_PIXELFORMAT;
ot->ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
ot->ddsd.ddsCaps.dwCaps2 = DDSCAPS2_HINTSTATIC;
#else
ot->ddsd.dwFlags =
DDSD_CAPS |
DDSD_HEIGHT |
DDSD_WIDTH |
DDSD_MIPMAPCOUNT |
DDSD_PIXELFORMAT;
ot->ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX;
ot->ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_HINTSTATIC;
#endif
ot->ddsd.ddpfPixelFormat = best_otf->ddpf;
HRESULT res = OS_frame.GetDirectDraw()->CreateSurface(
&ot->ddsd,
&ot->ddsurface,
NULL);
CBYTE *err;
switch(res)
{
case DDERR_INCOMPATIBLEPRIMARY : err = "DDERR_INCOMPATIBLEPRIMARY "; break;
case DDERR_INVALIDCAPS : err = "DDERR_INVALIDCAPS "; break;
case DDERR_INVALIDOBJECT : err = "DDERR_INVALIDOBJECT "; break;
case DDERR_INVALIDPARAMS : err = "DDERR_INVALIDPARAMS "; break;
case DDERR_INVALIDPIXELFORMAT : err = "DDERR_INVALIDPIXELFORMAT "; break;
case DDERR_NOALPHAHW : err = "DDERR_NOALPHAHW "; break;
case DDERR_NOCOOPERATIVELEVELSET : err = "DDERR_NOCOOPERATIVELEVELSET "; break;
case DDERR_NODIRECTDRAWHW : err = "DDERR_NODIRECTDRAWHW "; break;
case DDERR_NOEMULATION : err = "DDERR_NOEMULATION "; break;
case DDERR_NOEXCLUSIVEMODE : err = "DDERR_NOEXCLUSIVEMODE "; break;
case DDERR_NOFLIPHW : err = "DDERR_NOFLIPHW "; break;
case DDERR_NOMIPMAPHW : err = "DDERR_NOMIPMAPHW "; break;
case DDERR_NOOVERLAYHW : err = "DDERR_NOOVERLAYHW "; break;
case DDERR_NOZBUFFERHW : err = "DDERR_NOZBUFFERHW "; break;
case DDERR_OUTOFMEMORY : err = "DDERR_OUTOFMEMORY "; break;
case DDERR_OUTOFVIDEOMEMORY : err = "DDERR_OUTOFVIDEOMEMORY "; break;
case DDERR_PRIMARYSURFACEALREADYEXISTS : err = "DDERR_PRIMARYSURFACEALREADYEXISTS "; break;
case DDERR_UNSUPPORTEDMODE : err = "DDERR_UNSUPPORTEDMODE "; break;
case DD_OK:
err = "No error";
break;
default:
err = "Unknown error";
break;
}
ASSERT(res == DD_OK);
if (invert)
{
SLONG i;
SLONG j;
TGA_Pixel *tp;
//
// Invert the texture.
//
tp = data;
for (i = 0; i < ti.width; i++)
{
for (j = 0; j < ti.height; j++)
{
tp->alpha = 255 - tp->alpha;
tp->red = 255 - tp->red;
tp->green = 255 - tp->green;
tp->blue = 255 - tp->blue;
tp += 1;
}
}
}
//
// Lock the surface.
//
DDSURFACEDESC2 ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
VERIFY(ot->ddsurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) == DD_OK);
//
// Copy the tga data into the surface.
//
if (format != OS_TEXTURE_FORMAT_8)
{
SLONG i;
SLONG j;
UWORD pixel_our;
TGA_Pixel pixel_tga;
UWORD *wscreen = (UWORD *) ddsd.lpSurface;
//
// 16 bits per pixel.
//
for (i = 0; i < ti.width; i++)
{
for (j = 0; j < ti.height; j++)
{
pixel_tga = data[i + j * ti.width];
pixel_our = 0;
pixel_our |= (pixel_tga.red >> best_otf->mask_r) << best_otf->shift_r;
pixel_our |= (pixel_tga.green >> best_otf->mask_g) << best_otf->shift_g;
pixel_our |= (pixel_tga.blue >> best_otf->mask_b) << best_otf->shift_b;
if (best_otf->ddpf.dwFlags & DDPF_ALPHAPIXELS)
{
pixel_our |= (pixel_tga.alpha >> best_otf->mask_a) << best_otf->shift_a;
}
wscreen[i + j * (ddsd.lPitch >> 1)] = pixel_our;
}
}
}
else
{
SLONG i;
SLONG j;
UBYTE *wscreen = (UBYTE *) ddsd.lpSurface;
//
// 8 bits per pixel.
//
for (i = 0; i < ti.width; i++)
{
for (j = 0; j < ti.height; j++)
{
wscreen[i + j * ddsd.lPitch] = data[i + j * ti.width].red;
}
}
}
//
// Unlock the surface.
//
ot->ddsurface->Unlock(NULL);
//
// Query the texture interface from the surface.
//
VERIFY(ot->ddsurface->QueryInterface(IID_IDirect3DTexture2, (void **) &ot->ddtx) == DD_OK);
//
// Insert this texture into the array.
//
ot->next = OS_texture_head;
OS_texture_head = ot;
//
// Remember the size!
//
ot->size = ti.width;
return ot;
}
OS_Texture *OS_texture_create(SLONG size, SLONG format)
{
OS_Texture *ot;
OS_Tformat *otf;
//
// Make sure this texture is not too big.
//
{
D3DDEVICEDESC dh;
D3DDEVICEDESC ds;
memset(&dh, 0, sizeof(dh));
memset(&ds, 0, sizeof(ds));
dh.dwSize = sizeof(dh);
ds.dwSize = sizeof(ds);
VERIFY(OS_frame.GetD3DDevice()->GetCaps(&dh, &ds) == D3D_OK);
if (dh.dwFlags == 0)
{
//
// This must be software...
//
dh = ds;
}
if (size > dh.dwMaxTextureWidth ||
size > dh.dwMaxTextureHeight)
{
return NULL;
}
}
if (!OS_tformat[format].valid)
{
//
// The requested texture format does not exist. Is there
// another one we can try?
//
switch(format)
{
case OS_TEXTURE_FORMAT_8: format = OS_TEXTURE_FORMAT_RGB; break;
case OS_TEXTURE_FORMAT_1555: format = OS_TEXTURE_FORMAT_4444; break;
case OS_TEXTURE_FORMAT_4444: format = OS_TEXTURE_FORMAT_1555; break;
}
if (!OS_tformat[format].valid)
{
//
// We have no suitable texture format.
//
return NULL;
}
}
//
// The texture format we are going to use.
//
otf = &OS_tformat[format];
//
// Create a new texture.
//
ot = (OS_Texture *) malloc(sizeof(OS_Texture));
if (ot == NULL)
{
//
// It's really not worth checking for this... but anyway!
//
return NULL;
}
sprintf(ot->name, "Generated");
ot->format = format;
ot->size = size;
//
// Create a managed texture surface.
//
memset(&ot->ddsd, 0, sizeof(ot->ddsd));
ot->ddsd.dwSize = sizeof(DDSURFACEDESC2);
ot->ddsd.dwWidth = size;
ot->ddsd.dwHeight = size;
ot->ddsd.dwMipMapCount = 1;
#ifdef TARGET_DC
ot->ddsd.dwFlags =
DDSD_CAPS |
DDSD_HEIGHT |
DDSD_WIDTH |
DDSD_PIXELFORMAT;
ot->ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
ot->ddsd.ddsCaps.dwCaps2 = DDSCAPS2_HINTDYNAMIC;
#else
ot->ddsd.dwFlags =
DDSD_CAPS |
DDSD_HEIGHT |
DDSD_WIDTH |
DDSD_MIPMAPCOUNT |
DDSD_PIXELFORMAT;
ot->ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX;
ot->ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_HINTDYNAMIC;
#endif
ot->ddsd.ddpfPixelFormat = otf->ddpf;
if (OS_frame.GetDirectDraw()->CreateSurface(
&ot->ddsd,
&ot->ddsurface,
NULL) != DD_OK)
{
//
// Oh dear...
//
free(ot);
return NULL;
}
//
// The surface probably contains junk...
//
//
// Query the texture interface from the surface.
//
VERIFY(ot->ddsurface->QueryInterface(IID_IDirect3DTexture2, (void **) &ot->ddtx) == DD_OK);
//
// Insert this texture into the array.
//
ot->next = OS_texture_head;
OS_texture_head = ot;
return ot;
}
void OS_texture_finished_creating()
{
/*
SLONG i;
OS_Texture *ot;
OS_Point op;
UWORD index[3];
//
// Go through all the textures and draw something with them.
//
OS_scene_begin();
OS_init_renderstates();
for (ot = OS_texture_head; ot; ot = ot->next)
{
OS_page_lock(ot);
for (i = 0; i < 3; i++)
{
op.x = frand() * OS_screen_width;
op.y = frand() * OS_screen_height;
op.z = 0.5F;
op.rhw = 0.5F;
op.clip = OS_CLIP_TRANSFORMED;
index[i] = OS_page_add_point(ot, &op, 0x00000000, 0x00000000, frand(), frand(), 0.0F);
}
OS_page_add_triangle(ot, index[0], index[1], index[2]);
OS_page_unlock(ot);
OS_page_draw(ot, OS_TEXTURE_TYPE_DOUBLESIDED | OS_TEXTURE_TYPE_ZALWAYS);
}
OS_scene_end();
OS_show();
*/
}
SLONG OS_texture_size(OS_Texture *ot)
{
return ot->size;
}
SLONG OS_bitmap_format; // OS_TEXTURE_FORMAT_*
UWORD *OS_bitmap_uword_screen; // For 16-bit formats.
SLONG OS_bitmap_uword_pitch; // Pitch in UWORDS
UBYTE *OS_bitmap_ubyte_screen; // For the grayscale format.
SLONG OS_bitmap_ubyte_pitch; // Pitch in UBYTES
SLONG OS_bitmap_width;
SLONG OS_bitmap_height;
SLONG OS_bitmap_mask_r;
SLONG OS_bitmap_mask_g;
SLONG OS_bitmap_mask_b;
SLONG OS_bitmap_mask_a;
SLONG OS_bitmap_shift_r;
SLONG OS_bitmap_shift_g;
SLONG OS_bitmap_shift_b;
SLONG OS_bitmap_shift_a;
void OS_texture_lock(OS_Texture *ot)
{
OS_Tformat *otf;
HRESULT res;
DDSURFACEDESC2 ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
VERIFY((res = ot->ddsurface->Lock(
NULL,
&ddsd,
DDLOCK_WAIT |
DDLOCK_WRITEONLY |
DDLOCK_NOSYSLOCK,
NULL)) == DD_OK);
ASSERT(WITHIN(ot->format, 0, OS_TEXTURE_FORMAT_NUMBER - 1));
otf = &OS_tformat[ot->format];
if (ot->format == OS_TEXTURE_FORMAT_8)
{
//
// 8-bits per pixel.
//
OS_bitmap_ubyte_screen = (UBYTE *) ddsd.lpSurface;
OS_bitmap_ubyte_pitch = ddsd.lPitch;
OS_bitmap_uword_screen = NULL;
OS_bitmap_uword_pitch = 0;
}
else
{
OS_bitmap_ubyte_screen = NULL;
OS_bitmap_ubyte_pitch = 0;
OS_bitmap_uword_screen = (UWORD *) ddsd.lpSurface;
OS_bitmap_uword_pitch = ddsd.lPitch >> 1;
}
OS_bitmap_format = ot->format;
OS_bitmap_width = ddsd.dwWidth;
OS_bitmap_height = ddsd.dwHeight;
OS_bitmap_mask_r = otf->mask_r;
OS_bitmap_mask_g = otf->mask_g;
OS_bitmap_mask_b = otf->mask_b;
OS_bitmap_mask_a = otf->mask_a;
OS_bitmap_shift_r = otf->shift_r;
OS_bitmap_shift_g = otf->shift_g;
OS_bitmap_shift_b = otf->shift_b;
OS_bitmap_shift_a = otf->shift_a;
}
void OS_texture_unlock(OS_Texture *ot)
{
//
// Unlock the surface.
//
ot->ddsurface->Unlock(NULL);
}
// ========================================================
//
// PIPELINE SETUP AND VALIDATION
//
// ========================================================
void OS_init_renderstates()
{
LPDIRECT3DDEVICE3 d3d = OS_frame.GetD3DDevice();
//
// Setup renderstates.
//
d3d->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD);
d3d->SetRenderState(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE);
d3d->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE);
d3d->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, TRUE);
d3d->SetRenderState(D3DRENDERSTATE_SUBPIXEL, TRUE);
d3d->SetRenderState(D3DRENDERSTATE_ZENABLE, TRUE);
d3d->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
d3d->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE);
d3d->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CCW);
d3d->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
d3d->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
d3d->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
if (KEY_on[KEY_A])
{
d3d->SetRenderState(D3DRENDERSTATE_ANTIALIAS, D3DANTIALIAS_SORTINDEPENDENT);
}
else
{
d3d->SetRenderState(D3DRENDERSTATE_ANTIALIAS, D3DANTIALIAS_NONE);
}
//
// Setup pipeline for one-texture gouraud shaded.
//
d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
d3d->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
d3d->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
d3d->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
d3d->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
d3d->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE);
d3d->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFG_LINEAR);
d3d->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR);
d3d->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP);
d3d->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTFG_LINEAR);
d3d->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTFG_LINEAR);
d3d->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_WRAP);
//
// No alpha.
//
d3d->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
d3d->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
d3d->SetTextureStageState(2, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
}
//
// Works out how to setup the pipeline for additive and multiplicitive
// multi-texturing.
//
#define OS_METHOD_NUMBER_MUL 2
SLONG OS_pipeline_method_mul;
void OS_pipeline_calculate()
{
ULONG num_passes;
LPDIRECT3DDEVICE3 d3d = OS_frame.GetD3DDevice();
OS_pipeline_method_mul = 0;
OS_Texture *ot1 = OS_texture_create(32, OS_TEXTURE_FORMAT_RGB);
OS_Texture *ot2 = OS_texture_create(32, OS_TEXTURE_FORMAT_RGB);
while(1)
{
OS_init_renderstates();
d3d->SetTexture(0, ot1->ddtx);
d3d->SetTexture(1, ot2->ddtx);
switch(OS_pipeline_method_mul)
{
case 1:
d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
d3d->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
d3d->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
break;
case 0:
d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
d3d->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
d3d->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
d3d->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_MODULATE);
d3d->SetTextureStageState(2, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
d3d->SetTextureStageState(2, D3DTSS_COLORARG2, D3DTA_CURRENT);
break;
default:
//
// Didn't find any way to do mulitexturing!
//
break;
}
if (OS_pipeline_method_mul == OS_METHOD_NUMBER_MUL)
{
//
// No multitexturing! :(
//
break;
}
if (d3d->ValidateDevice(&num_passes) == D3D_OK)
{
if (num_passes != 0)
{
//
// Found a methed for doing additive multi-texturing.
//
OS_string("Validated %d with %d passes\n", OS_pipeline_method_mul, num_passes);
break;
}
}
OS_pipeline_method_mul += 1;
}
OS_string("Multitexture method %d\n", OS_pipeline_method_mul);
}
void OS_change_renderstate_for_type(ULONG draw)
{
LPDIRECT3DDEVICE3 d3d = OS_frame.GetD3DDevice();
if (draw & OS_DRAW_ADD)
{
d3d->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
d3d->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE);
d3d->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE);
}
if (draw & OS_DRAW_MULTIPLY)
{
d3d->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
d3d->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_DESTCOLOR);
d3d->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_SRCCOLOR);
}
if (draw & OS_DRAW_MULBYONE)
{
d3d->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
d3d->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_DESTCOLOR);
d3d->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO);
}
if (draw & OS_DRAW_CLAMP)
{
d3d->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
}
if (draw & OS_DRAW_DECAL)
{
d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
}
if (draw & OS_DRAW_TRANSPARENT)
{
d3d->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
d3d->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ZERO);
d3d->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE);
}
if (draw & OS_DRAW_DOUBLESIDED)
{
d3d->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
}
if (draw & OS_DRAW_NOZWRITE)
{
d3d->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
}
if (draw & OS_DRAW_ALPHAREF)
{
d3d->SetRenderState(D3DRENDERSTATE_ALPHAFUNC,D3DCMP_NOTEQUAL);
d3d->SetRenderState(D3DRENDERSTATE_ALPHAREF,0);
d3d->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE,TRUE);
//
// Make sure the alpha from the texture gets through.
//
d3d->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
}
if (draw & OS_DRAW_ZREVERSE)
{
d3d->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_GREATEREQUAL);
}
if (draw & OS_DRAW_ZALWAYS)
{
d3d->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_ALWAYS);
}
if (draw & OS_DRAW_CULLREVERSE)
{
d3d->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CW);
}
if (draw & OS_DRAW_NODITHER)
{
d3d->SetRenderState(D3DRENDERSTATE_DITHERENABLE, FALSE);
}
if (draw & OS_DRAW_ALPHABLEND)
{
d3d->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
d3d->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
d3d->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
d3d->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
d3d->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
}
if (draw & OS_DRAW_TEX_NONE)
{
d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
}
if (draw & OS_DRAW_TEX_MUL)
{
switch(OS_pipeline_method_mul)
{
case 1:
if (draw & OS_DRAW_DECAL)
{
//
// Don't multiply by diffuse colour...
//
d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
}
else
{
d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
}
d3d->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
d3d->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
break;
case 0:
d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
d3d->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
d3d->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
if (draw & OS_DRAW_DECAL)
{
//
// Don't multiply by diffuse colour...
//
}
else
{
d3d->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_MODULATE);
d3d->SetTextureStageState(2, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
d3d->SetTextureStageState(2, D3DTSS_COLORARG2, D3DTA_CURRENT);
}
break;
default:
break;
}
}
if (draw & OS_DRAW_NOFILTER)
{
d3d->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFG_POINT);
d3d->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_POINT);
d3d->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTFG_POINT);
d3d->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTFG_POINT);
}
}
void OS_undo_renderstate_type_changes(void)
{
LPDIRECT3DDEVICE3 d3d = OS_frame.GetD3DDevice();
d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
d3d->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
d3d->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3d->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
d3d->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE);
d3d->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP);
d3d->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
d3d->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CCW);
d3d->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE);
d3d->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
d3d->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
d3d->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE);
d3d->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFG_LINEAR);
d3d->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR);
d3d->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTFG_LINEAR);
d3d->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTFG_LINEAR);
}
// ========================================================
//
// WINDOWS STUFF
//
// ========================================================
void OS_string(CBYTE *fmt, ...)
{
//
// Work out the real message.
//
CBYTE message[512];
va_list ap;
va_start(ap, fmt);
vsprintf(message, fmt, ap);
va_end (ap);
OutputDebugString(message);
}
SLONG OS_game_start_tick_count;
SLONG OS_ticks(void)
{
return GetTickCount() - OS_game_start_tick_count;
}
void OS_ticks_reset()
{
OS_game_start_tick_count = GetTickCount();
}
SLONG OS_mhz;
//
// Returns TRUE if the processor has support for the RDTSC instruction.
//
SLONG OS_has_rdtsc(void)
{
SLONG res;
_asm
{
mov eax, 0
cpuid
mov res, eax
}
if (res == 0)
{
//
// This is an old 486!
//
return FALSE;
}
//
// Check the processor feature info.
//
_asm
{
mov eax, 1
cpuid
mov res, edx
}
if (res & (1 << 4))
{
return TRUE;
}
else
{
return FALSE;
}
}
//
// Returns the number of processor ticks since the processor was reset / 65536
//
ULONG OS_rdtsc(void)
{
ULONG hi;
ULONG lo;
_asm
{
rdtsc
mov hi, edx
mov lo, eax
}
ULONG ans;
ans = lo >> 16;
ans |= hi << 16;
return ans;
}
void OS_work_out_mhz(void)
{
if (OS_has_rdtsc())
{
SLONG tick;
ULONG tsc1 = OS_rdtsc();
//
// Wait a second.
//
tick = OS_ticks();
while(OS_ticks() < tick + 1000);
ULONG tsc2 = OS_rdtsc();
float persec = float(tsc2 - tsc1);
persec *= 65536.0F / 1000000.0F;
OS_mhz = SLONG(persec);
}
else
{
//
// It must be a 486... lets say its 66Mhz and be hopeful.
//
OS_mhz = 66;
}
}
SLONG OS_processor_mhz(void)
{
return OS_mhz;
}
// ========================================================
//
// MOUSE STUFF
//
// ========================================================
void OS_mouse_get(SLONG *x, SLONG *y)
{
POINT point;
GetCursorPos(&point);
*x = point.x;
*y = point.y;
}
void OS_mouse_set(SLONG x, SLONG y)
{
SetCursorPos(x, y);
}
#if 0
LRESULT CALLBACK OS_message_handler(
HWND window_handle,
UINT message_type,
WPARAM param_w,
LPARAM param_l)
{
UBYTE scancode;
switch(message_type)
{
case WM_PAINT:
//
// The user callback function does all the screen drawing.
// Do enough to appease windows.
//
HDC device_context_handle;
PAINTSTRUCT paintstruct;
device_context_handle = BeginPaint(window_handle, &paintstruct);
EndPaint(window_handle, &paintstruct);
return 0;
case WM_KEYDOWN:
case WM_KEYUP:
//
// Keyboard stuff.
//
scancode = (param_l >> 16) & 0xff;
scancode |= (param_l >> 17) & 0x80;
if (message_type == WM_KEYDOWN)
{
KEY_on[scancode] = 1;
KEY_inkey = scancode;
}
else
{
KEY_on[scancode] = 0;
}
//
// Alt keys don't work.
//
KEY_on[KEY_LALT] = 0;
KEY_on[KEY_RALT] = 0;
//
// Check for shift/alt/control keys.
//
KEY_shift = 0;
if (KEY_on[KEY_LSHIFT ] || KEY_on[KEY_RSHIFT ]) KEY_shift |= KEY_SHIFT;
if (KEY_on[KEY_LCONTROL] || KEY_on[KEY_RCONTROL]) KEY_shift |= KEY_CONTROL;
if (KEY_on[KEY_LALT ] || KEY_on[KEY_RALT ]) KEY_shift |= KEY_ALT;
return 0;
case WM_MOVE:
//
// Tell the frame about the new position of the window.
//
OS_frame.Move(LOWORD(param_l),HIWORD(param_l));
//
// Fall through to the default handling.
//
break;
default:
break;
}
//
// Just let windows do its normal thing.
//
return DefWindowProc(
window_handle,
message_type,
param_w,
param_l);
}
#endif
SLONG OS_process_messages()
{
SHELL_ACTIVE;
if (Keys[KB_ESC])
{
Keys[KB_ESC] = 0;
KEY_on[KEY_ESCAPE] = TRUE;
}
return OS_CARRY_ON;
MSG msg;
int ret;
//
// Poll the joystick.
//
OS_joy_poll();
while(1)
{
if (!PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE))
{
//
// No messages pending.
//
return OS_CARRY_ON;
}
ret = GetMessage(&msg, NULL, 0, 0);
if (ret == 0 || ret == -1)
{
//
// Kill the game!
//
return OS_QUIT_GAME;
}
DispatchMessage(&msg);
}
}
#if 0
//
// Valid devices.
//
typedef struct
{
D3DEnum_DriverInfo *driver;
D3DEnum_DeviceInfo *device;
D3DEnum_ModeInfo *mode; // NULL => Use windowed mode.
} OS_Mode;
#define OS_MAX_MODES 16
OS_Mode OS_mode[OS_MAX_MODES];
SLONG OS_mode_upto;
SLONG OS_mode_sel;
//
// Finds the valid devices from the D3DEnumerated choice and set
// the OS_mode_sel to the default.
//
void OS_mode_init()
{
SLONG i;
D3DEnum_DriverInfo *vi;
D3DEnum_DeviceInfo *ci;
D3DEnum_ModeInfo *mi; // NULL => Use windowed mode.
OS_mode_upto = 0;
OS_mode_sel = 0;
SLONG lookfor640x480;
SLONG lookfor512x384;
//
// Find all valid modes.
//
for (vi = D3DEnum_GetFirstDriver(); vi; vi = vi->pNext)
{
for (ci = vi->pFirstDevice; ci; ci = ci->pNext)
{
if (ci->bIsHardware)
{
//
// Found a hardware device.
//
if (WITHIN(OS_mode_upto, 0, OS_MAX_MODES - 1))
{
OS_mode[OS_mode_upto].driver = vi;
OS_mode[OS_mode_upto].device = ci;
OS_mode[OS_mode_upto].mode = NULL;
#ifdef NDEBUG
lookfor512x384 = FALSE;//(vi != D3DEnum_GetFirstDriver());
lookfor640x480 = TRUE;
#else
lookfor512x384 = FALSE;
lookfor640x480 = !ci->bWindowed;
#endif
if (lookfor512x384)
{
//
// Look for the first 512x384 mode.
//
for (mi = ci->pFirstMode; mi; mi = mi->pNext)
{
if (mi->ddsd.dwWidth == 512 &&
mi->ddsd.dwHeight == 384)
{
OS_mode[OS_mode_upto].mode = mi;
//
// We already have our mode.
//
lookfor640x480 = FALSE;
break;
}
}
}
if (lookfor640x480)
{
//
// Look for the first 640x480 mode.
//
for (mi = ci->pFirstMode; mi; mi = mi->pNext)
{
if (mi->ddsd.dwWidth == 640 &&
mi->ddsd.dwHeight == 480)
{
OS_mode[OS_mode_upto].mode = mi;
break;
}
}
}
if (OS_mode[OS_mode_upto].mode == NULL)
{
//
// Make sure this device support windowed mode!
//
if (OS_mode[OS_mode_upto].device->bWindowed)
{
//
// We are ok.
//
}
else
{
//
// Use the first available mode.
//
OS_mode[OS_mode_upto].mode = OS_mode[OS_mode_upto].device->pFirstMode;
}
}
OS_mode_upto += 1;
}
}
}
}
#ifndef NDEBUG
//
// In debug build choose the first windowed mode.
//
for (i = 0; i < OS_mode_upto; i++)
{
if (OS_mode[i].device->bWindowed)
{
OS_mode_sel = i;
}
}
#else
//
// In release build choose the last mode.
//
OS_mode_sel = OS_mode_upto - 1;
#endif
}
//
// Adds the modes for the current selection to the combo box.
//
void OS_mydemo_setup_mode_combo(HWND combo_handle, SLONG mode)
{
SLONG index;
ASSERT(WITHIN(mode, 0, OS_mode_upto - 1));
//
// Clear all old modes.
//
SendMessage(combo_handle, CB_RESETCONTENT, 0, 0);
//
// Add each mode.
//
D3DEnum_ModeInfo *mi;
if (OS_mode[mode].device->bWindowed)
{
index = SendMessage(combo_handle, CB_ADDSTRING, 0, (LPARAM) "In a window");
SendMessage(combo_handle, CB_SETITEMDATA, (WPARAM) index, (LPARAM) NULL);
if (NULL == OS_mode[mode].mode)
{
//
// This is the current selection.
//
SendMessage(combo_handle, CB_SETCURSEL, index, 0);
}
}
for (mi = OS_mode[mode].device->pFirstMode; mi; mi = mi->pNext)
{
index = SendMessage(combo_handle, CB_ADDSTRING, 0, (LPARAM) mi->strDesc);
SendMessage(combo_handle, CB_SETITEMDATA, (WPARAM) index, (LPARAM) mi);
if (mi == OS_mode[mode].mode)
{
//
// This is the current selection.
//
SendMessage(combo_handle, CB_SETCURSEL, index, 0);
}
}
}
//
// The callback function for the MyDemo dialog box.
//
#define OS_MYDEMO_RUN 1
#define OS_MYDEMO_EXIT 2
BOOL CALLBACK OS_mydemo_proc(
HWND dialog_handle,
UINT message_type,
WPARAM param_w,
LPARAM param_l)
{
SLONG i;
SLONG d;
SLONG res;
SLONG index;
RECT rect;
HWND combo_handle;
D3DEnum_DriverInfo *vi;
D3DEnum_DeviceInfo *ci;
switch(message_type)
{
case WM_INITDIALOG:
//
// Fill out the list boxes with the correct values. First find
// all compatible
//
combo_handle = GetDlgItem(dialog_handle, IDC_COMBO_DRIVER);
for (i = 0; i < OS_mode_upto; i++)
{
SendMessage(combo_handle, CB_ADDSTRING, 0, (LPARAM) OS_mode[i].driver->strDesc);
}
//
// Set the current selection.
//
SendMessage(combo_handle, CB_SETCURSEL, OS_mode_sel, 0);
//
// Add the modes for the current selection.
//
combo_handle = GetDlgItem(dialog_handle, IDC_COMBO_MODE);
OS_mydemo_setup_mode_combo(combo_handle, OS_mode_sel);
return TRUE;
case WM_COMMAND:
switch(LOWORD(param_w))
{
case IDOK:
EndDialog(dialog_handle, OS_MYDEMO_RUN);
return TRUE;
case IDCANCEL:
EndDialog(dialog_handle, OS_MYDEMO_EXIT);
return TRUE;
case IDC_COMBO_DRIVER:
switch(HIWORD(param_w))
{
case CBN_SELCHANGE:
//
// Change the list of modes.
//
OS_mode_sel = SendMessage((HWND) param_l, CB_GETCURSEL, 0, 0);
ASSERT(WITHIN(OS_mode_sel, 0, OS_mode_upto - 1));
OS_mydemo_setup_mode_combo(
GetDlgItem(dialog_handle, IDC_COMBO_MODE),
OS_mode_sel);
break;
}
break;
case IDC_COMBO_MODE:
switch(HIWORD(param_w))
{
case CBN_SELCHANGE:
//
// Update the current mode.
//
index = SendMessage((HWND) param_l, CB_GETCURSEL, 0, 0);
ASSERT(WITHIN(OS_mode_sel, 0, OS_mode_upto - 1));
OS_mode[OS_mode_sel].mode = (D3DEnum_ModeInfo * /* We hope */) SendMessage((HWND) param_l, CB_GETITEMDATA, (WPARAM) index, 0);
break;
}
break;
}
break;
case WM_CLOSE:
EndDialog(dialog_handle, OS_MYDEMO_EXIT);
return TRUE;
}
return FALSE;
}
#endif
#if 0
//
// The entry point of the program.
//
int WINAPI WinMain(
HINSTANCE this_instance,
HINSTANCE last_instance,
LPSTR command_line,
int start_show_state)
{
HRESULT res;
//
// Remember the arguments passed to this function.
//
OS_this_instance = this_instance;
OS_last_instance = last_instance;
OS_command_line = command_line;
OS_start_show_state = start_show_state;
OS_wcl.hInstance = this_instance;
OS_wcl.lpszClassName = OS_application_name;
OS_wcl.lpfnWndProc = OS_message_handler;
OS_wcl.style = 0;
OS_wcl.cbSize = sizeof(WNDCLASSEX);
OS_wcl.cbClsExtra = 0;
OS_wcl.cbWndExtra = 0;
OS_wcl.lpszMenuName = NULL;
OS_wcl.hIcon = LoadIcon(this_instance, MAKEINTRESOURCE(IDI_ICON1));
OS_wcl.hIconSm = NULL;//LoadIcon(this_instance, MAKEINTRESOURCE(IDI_ICON1));
OS_wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
OS_wcl.hbrBackground = (HBRUSH) GetStockObject(GRAY_BRUSH);
//
// Register the window class.
//
if (RegisterClassEx(&OS_wcl) == 0)
{
//
// Could not register the window class!
//
return 0;
}
//
// Create a window 640 x 480.
//
RECT rect;
rect.left = 100 + 0;
rect.right = 100 + 640;
rect.top = 100 + 0;
rect.bottom = 100 + 480;
if (AdjustWindowRect(
&rect,
WS_CAPTION,
FALSE) == 0)
{
rect.right -= 200;
rect.left += 200;
}
else
{
OS_window_handle = CreateWindow(
OS_application_name,
OS_application_name,
WS_CAPTION | WS_SYSMENU,
50,
50,
rect.right - rect.left,
rect.bottom - rect.top,
NULL,
NULL,
this_instance,
NULL);
}
//
// Make sure it worked.
//
if (OS_window_handle == 0)
{
return 0;
}
//
// Initialise joystick control.
//
OS_joy_init();
/*
//
// Initialise MIDAS
//
MIDASstartup();
MIDASsetOption(MIDAS_OPTION_DSOUND_MODE, MIDAS_DSOUND_FORCE_STREAM);
MIDASsetOption(MIDAS_OPTION_DSOUND_HWND, (DWORD) OS_window_handle);
MIDASsetOption(MIDAS_OPTION_DSOUND_BUFLEN, 2000);
MIDASsetOption(MIDAS_OPTION_OUTPUTMODE, MIDAS_MODE_16BIT_STEREO);
while(1)
{
if (MIDASinit())
{
OS_midas_ok = TRUE;
break;
}
else
{
//
// Could not initialise MIDAS.
//
if (MessageBox(
OS_window_handle,
"Could not initialise sound. If another application is using sound close that application and select Retry. Otherwise click Cancel to run the demo without sound.",
"Beat",
MB_ICONERROR | MB_RETRYCANCEL) == IDCANCEL)
{
//
// No sound.
//
break;
}
}
}
*/
// if (OS_midas_ok)
// {
// MIDASstartBackgroundPlay(0);
// }
//
// Find out the speed of the machine we are running on.
//
OS_work_out_mhz();
//
// Enumerate the devices.
//
D3DEnum_EnumerateDevices(NULL);
D3DEnum_DriverInfo *di = D3DEnum_GetFirstDriver();
//
// Find valid modes.
//
OS_mode_init();
if (OS_mode_upto == 0)
{
//
// No valid screen mode!
//
MessageBox(
OS_window_handle,
"Could not find a 3d accelerator card. Make sure that you have DirectX 6.0 or higher installed.", "Beat", MB_ICONERROR | MB_OK);
exit(1);
}
have_another_go:;
//
// Promt the user to choose a mode.
//
switch(DialogBox(
OS_this_instance,
MAKEINTRESOURCE(IDD_DRIVERS),
OS_window_handle,
OS_mydemo_proc))
{
case OS_MYDEMO_RUN:
break;
case OS_MYDEMO_EXIT:
//
// Close gracefully...
//
D3DEnum_FreeResources();
//MIDASstopBackgroundPlay();
//MIDASclose();
return 0;
default:
exit(1);
break;
}
{
GUID *driver;
GUID *device;
DDSURFACEDESC2 *display_mode;
BOOL is_windowed;
BOOL is_hardware;
#if WE_USE_THE_DEFAULT_DIALOG_BOX
//
// Prompt the user for a device and a driver.
//
INT ret = D3DEnum_UserDlgSelectDriver(OS_window_handle, TRUE);
D3DEnum_GetSelectedDriver(
&driver,
&device,
&display_mode,
&is_windowed,
&is_hardware);
OS_frame_is_fullscreen = !is_windowed;
OS_frame_is_hardware = is_hardware;
#else
driver = OS_mode[OS_mode_sel].driver->pGUID;
device = OS_mode[OS_mode_sel].device->pGUID;
if (OS_mode[OS_mode_sel].mode)
{
display_mode = &OS_mode[OS_mode_sel].mode->ddsd;
OS_frame_is_fullscreen = TRUE;
OS_frame_is_hardware = TRUE;
}
else
{
display_mode = NULL;
OS_frame_is_fullscreen = FALSE;
OS_frame_is_hardware = TRUE;
}
#endif
//
// Initialise the framework.
//
DWORD flags;
flags = 0;
flags |= D3DFW_BACKBUFFER;
flags |= D3DFW_ZBUFFER;
flags |= D3DFW_NO_FPUSETUP; // We are doing deep mandlebrot!
if (OS_frame_is_fullscreen)
{
flags |= D3DFW_FULLSCREEN;
}
res = OS_frame.Initialize(
OS_window_handle,
driver,
device,
display_mode,
flags);
if (res == S_OK)
{
if (OS_frame_is_fullscreen)
{
//
// Hide the mouse.
//
ShowCursor(FALSE);
//
// Makes the window not redraw itself when we go fullscreen.
//
SetWindowLong(OS_window_handle, GWL_STYLE, WS_POPUP);
}
else
{
//
// Show our window!
//
ShowWindow(OS_window_handle, SW_SHOW);
}
//
// Enumerate texture formats.
//
{
int i;
OS_Tformat *otf;
//
// Find the texture formats.
//
OS_frame.GetD3DDevice()->EnumTextureFormats(OS_texture_enumerate_pixel_formats, NULL);
//
// Set the masks and shifts for each texture format.
//
for (i = 0; i < OS_TEXTURE_FORMAT_NUMBER; i++)
{
otf = &OS_tformat[i];
if (i == OS_TEXTURE_FORMAT_8)
{
//
// We don't have to set the masks and shifts for grayscale textures.
//
continue;
}
if (otf->valid)
{
//
// Calculate the masks and shifts.
//
OS_calculate_mask_and_shift(otf->ddpf.dwRBitMask, &otf->mask_r, &otf->shift_r);
OS_calculate_mask_and_shift(otf->ddpf.dwGBitMask, &otf->mask_g, &otf->shift_g);
OS_calculate_mask_and_shift(otf->ddpf.dwBBitMask, &otf->mask_b, &otf->shift_b);
if (otf->ddpf.dwFlags & DDPF_ALPHAPIXELS)
{
OS_calculate_mask_and_shift(otf->ddpf.dwRGBAlphaBitMask, &otf->mask_a, &otf->shift_a);
}
}
}
}
//
// What is the screen-res?
//
RECT *dimensions = OS_frame.GetViewportRect();
OS_screen_width = float(dimensions->right);
OS_screen_height = float(dimensions->bottom);
//
// Make the fast floating point to SLONG conversion macro work. It
// changes the default setting of the floating point unit to truncate
// instead of round-to-nearest.
//
ftol_init();
//
// Work out how to multi-texture
//
OS_pipeline_calculate();
//
// Time relative to the beginning of the program.
//
OS_game_start_tick_count = GetTickCount();
//
// Start the game.
//
MAIN_main();
//
// Clean up.
//
OS_frame.DestroyObjects();
}
else
{
//
// Could not set that mode!
//
CBYTE *err;
if (res == D3DFWERR_NOZBUFFER)
{
err = "There was not enough memory to create the zbuffer. Try using a lower resolution mode.";
}
else
{
err = "Could not setup the display using those settings. Try changing driver or using another mode.";
}
MessageBox(
OS_window_handle,
err,
"Beat",
MB_ICONERROR | MB_OK);
//
// Have another go...
//
goto have_another_go;
}
}
//
// Free all enumeration resources.
//
D3DEnum_FreeResources();
//
// Shutdown MIDAS
//
/*
if (OS_module_handle)
{
MIDASstopModule(OS_module_handle);
OS_module_handle = NULL;
}
if (OS_module)
{
MIDASfreeModule(OS_module);
OS_module = NULL;
}
if (OS_midas_ok)
{
MIDASstopBackgroundPlay();
}
*/
//MIDASclose();
return 0;
}
#endif
// ========================================================
//
// ROTATING POINTS
//
// ========================================================
//
// The camera and the screen.
//
float OS_cam_x;
float OS_cam_y;
float OS_cam_z;
float OS_cam_aspect;
float OS_cam_lens;
float OS_cam_view_dist;
float OS_cam_over_view_dist;
float OS_cam_matrix[9];
float OS_cam_view_matrix[9];
float OS_cam_screen_x1;
float OS_cam_screen_y1;
float OS_cam_screen_x2;
float OS_cam_screen_y2;
float OS_cam_screen_width;
float OS_cam_screen_height;
float OS_cam_screen_mid_x;
float OS_cam_screen_mid_y;
float OS_cam_screen_mul_x;
float OS_cam_screen_mul_y;
void OS_camera_set(
float world_x,
float world_y,
float world_z,
float view_dist,
float yaw,
float pitch,
float roll,
float lens,
float screen_x1,
float screen_y1,
float screen_x2,
float screen_y2)
{
OS_cam_screen_x1 = screen_x1 * OS_screen_width;
OS_cam_screen_y1 = screen_y1 * OS_screen_height;
OS_cam_screen_x2 = screen_x2 * OS_screen_width;
OS_cam_screen_y2 = screen_y2 * OS_screen_height;
OS_cam_screen_width = OS_cam_screen_x2 - OS_cam_screen_x1;
OS_cam_screen_height = OS_cam_screen_y2 - OS_cam_screen_y1;
OS_cam_screen_mid_x = OS_cam_screen_x1 + OS_cam_screen_width * 0.5F;
OS_cam_screen_mid_y = OS_cam_screen_y1 + OS_cam_screen_height * 0.5F;
OS_cam_screen_mul_x = OS_cam_screen_width * 0.5F / OS_ZCLIP_PLANE;
OS_cam_screen_mul_y = OS_cam_screen_height * 0.5F / OS_ZCLIP_PLANE;
OS_cam_x = world_x;
OS_cam_y = world_y;
OS_cam_z = world_z;
OS_cam_lens = lens;
OS_cam_view_dist = view_dist;
OS_cam_over_view_dist = 1.0F / view_dist;
OS_cam_aspect = OS_cam_screen_height / OS_cam_screen_width;
MATRIX_calc(
OS_cam_matrix,
yaw,
pitch,
roll);
memcpy(OS_cam_view_matrix, OS_cam_matrix, sizeof(OS_cam_view_matrix));
MATRIX_skew(
OS_cam_matrix,
OS_cam_aspect,
OS_cam_lens,
OS_cam_over_view_dist); // Shrink the matrix down so the furthest point has a view distance z of 1.0F
}
OS_Trans OS_trans[OS_MAX_TRANS];
SLONG OS_trans_upto;
void OS_transform(
float world_x,
float world_y,
float world_z,
OS_Trans *os)
{
os->x = world_x - OS_cam_x;
os->y = world_y - OS_cam_y;
os->z = world_z - OS_cam_z;
MATRIX_MUL(
OS_cam_matrix,
os->x,
os->y,
os->z);
os->clip = OS_CLIP_ROTATED;
if (os->z < OS_ZCLIP_PLANE)
{
os->clip |= OS_CLIP_NEAR;
return;
}
else
if (os->z > 1.0F)
{
os->clip |= OS_CLIP_FAR;
return;
}
else
{
//
// The z-range of the point is okay.
//
os->Z = OS_ZCLIP_PLANE / os->z;
os->X = OS_cam_screen_mid_x + OS_cam_screen_mul_x * os->x * os->Z;
os->Y = OS_cam_screen_mid_y - OS_cam_screen_mul_y * os->y * os->Z;
//
// Set the clipping flags.
//
os->clip |= OS_CLIP_TRANSFORMED;
if (os->X < 0.0F ) {os->clip |= OS_CLIP_LEFT;}
else if (os->X > OS_screen_width) {os->clip |= OS_CLIP_RIGHT;}
if (os->Y < 0.0F ) {os->clip |= OS_CLIP_TOP;}
else if (os->Y > OS_screen_height) {os->clip |= OS_CLIP_BOTTOM;}
return;
}
}
// ========================================================
//
// DRAWING STUFF
//
// ========================================================
void OS_clear_screen(UBYTE r, UBYTE g, UBYTE b, float z)
{
CLEAR_VIEWPORT;
/*
ULONG colour = (r << 16) | (g << 8) | (b << 0);
HRESULT ret = OS_frame.GetViewport()->Clear2(
1,
(D3DRECT *) OS_frame.GetViewportRect(),
D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
colour,
z,
0);
*/
}
void OS_scene_begin()
{
OS_frame.GetD3DDevice()->BeginScene();
//
// Set the render states to their default values.
//
OS_init_renderstates();
}
void OS_scene_end()
{
OS_frame.GetD3DDevice()->EndScene();
}
void OS_fps()
{
SLONG i;
static SLONG fps = 0;
static SLONG last_time = 0;
static SLONG last_frame_count = 0;
static SLONG frame_count = 0;
float x1;
float y1;
float x2;
float y2;
float tick;
SLONG now;
now = OS_ticks();
frame_count += 1;
if (now >= last_time + 1000)
{
fps = frame_count - last_frame_count;
last_frame_count = frame_count;
last_time = now;
}
OS_Buffer *ob = OS_buffer_new();
for (i = 0; i < fps; i++)
{
switch((i + 1) % 10)
{
case 0:
tick = 8.0F;
break;
case 5:
tick = 5.0F;
break;
default:
tick = 3.0F;
break;
}
x1 = 5.0F + i * 4.0F;
y1 = 5.0F;
x2 = 5.0F + i * 4.0F + 2.0F;
y2 = 5.0F + tick;
x1 /= OS_screen_width;
y1 /= OS_screen_height;
x2 /= OS_screen_width;
y2 /= OS_screen_height;
OS_buffer_add_sprite(
ob,
x1,
y1,
x2,
y2,
0.0F, 1.0F,
0.0F, 1.0F,
0.0F,
0x00ffffff,
0x00000000,
OS_FADE_BOTTOM);
}
OS_buffer_draw(ob, NULL);
}
void OS_show()
{
FLIP(NULL, DDFLIP_WAIT);
}
//
// Our flexible vertex format.
//
typedef struct
{
float sx;
float sy;
float sz;
float rhw;
ULONG colour;
ULONG specular;
float tu1;
float tv1;
float tu2;
float tv2;
} OS_Flert;
#define OS_FLERT_FORMAT (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2)
// ========================================================
//
// BUFFER STUFF
//
// ========================================================
typedef struct os_buffer
{
SLONG num_flerts;
SLONG num_indices;
SLONG max_flerts;
SLONG max_indices;
OS_Flert *flert;
UWORD *index;
OS_Buffer *next;
} OS_Buffer;
OS_Buffer *OS_buffer_free;
//
// Creates a new buffer.
//
OS_Buffer *OS_buffer_create(void)
{
//
// Allocate the buffer.
//
OS_Buffer *ob = (OS_Buffer *) malloc(sizeof(OS_Buffer));
//
// Initialise the buffer.
//
ob->max_flerts = 256;
ob->max_indices = 1024;
ob->num_flerts = 0;
ob->num_indices = 1;
ob->flert = (OS_Flert *) malloc(sizeof(OS_Flert) * ob->max_flerts );
ob->index = (UWORD *) malloc(sizeof(UWORD ) * ob->max_indices);
memset(ob->flert, 0, sizeof(OS_Flert) * ob->max_flerts );
memset(ob->index, 0, sizeof(UWORD ) * ob->max_indices);
ob->next = NULL;
return ob;
}
//
// Gets a buffer from the linked list of free buffers. If the free list is empty,
// it creates a new one.
//
OS_Buffer *OS_buffer_get(void)
{
OS_Buffer *ans;
if (OS_buffer_free)
{
ans = OS_buffer_free;
OS_buffer_free = OS_buffer_free->next;
ans->next = NULL;
}
else
{
ans = OS_buffer_create();
}
return ans;
}
//
// Returns a buffer to the free list.
//
void OS_buffer_give(OS_Buffer *ob)
{
ob->next = OS_buffer_free;
OS_buffer_free = ob;
}
OS_Buffer *OS_buffer_new(void)
{
OS_Buffer *ob = OS_buffer_get();
ob->num_indices = 0;
ob->num_flerts = 1;
return ob;
}
//
// Grows the size of the flert array.
//
void OS_buffer_grow_flerts(OS_Buffer *ob)
{
ob->max_flerts *= 2;
ob->flert = (OS_Flert *) realloc(ob->flert, ob->max_flerts * sizeof(OS_Flert));
}
void OS_buffer_grow_indices(OS_Buffer *ob)
{
ob->max_indices *= 2;
ob->index = (UWORD *) realloc(ob->index, ob->max_indices * sizeof(UWORD));
}
void OS_buffer_add_vert(OS_Buffer *ob, OS_Vert *ov)
{
OS_Trans *ot;
OS_Flert *of;
//
// Make sure we've got enough room for another vertex.
//
if (ob->num_flerts >= ob->max_flerts)
{
//
// We need a bigger buffer.
//
OS_buffer_grow_flerts(ob);
}
ASSERT(WITHIN(ov->trans, 0, OS_MAX_TRANS - 1));
of = &ob->flert[ob->num_flerts];
ot = &OS_trans [ov->trans];
//
// Create the new tlvertex.
//
of->sx = ot->X;
of->sy = ot->Y;
of->sz = 1.0F - ot->Z; //ot->z;
of->rhw = ot->Z;
of->colour = ov->colour;
of->specular = ov->specular;
of->tu1 = ov->u1;
of->tv1 = ov->v1;
of->tu2 = ov->u2;
of->tv2 = ov->v2;
//
// Store the index of the flert inside the vertex.
//
ov->index = ob->num_flerts++;
}
void OS_buffer_add_triangle(
OS_Buffer *ob,
OS_Vert *ov1,
OS_Vert *ov2,
OS_Vert *ov3)
{
ULONG clip_and =
OS_trans[ov1->trans].clip &
OS_trans[ov2->trans].clip &
OS_trans[ov3->trans].clip;
if (clip_and & OS_CLIP_TRANSFORMED)
{
if (clip_and & OS_CLIP_OFFSCREEN)
{
//
// The triangle is completely off-screen.
//
return;
}
else
{
if (ov1->index == NULL) {OS_buffer_add_vert(ob, ov1);}
if (ov2->index == NULL) {OS_buffer_add_vert(ob, ov2);}
if (ov3->index == NULL) {OS_buffer_add_vert(ob, ov3);}
//
// Add this triangle. All the points are transformed and at least
// one is on screen.
//
if (ob->num_indices + 3 > ob->max_indices)
{
//
// Need a bigger buffer.
//
OS_buffer_grow_indices(ob);
}
ob->index[ob->num_indices++] = ov1->index;
ob->index[ob->num_indices++] = ov2->index;
ob->index[ob->num_indices++] = ov3->index;
return;
}
}
else
{
ULONG clip_or =
OS_trans[ov1->trans].clip |
OS_trans[ov2->trans].clip |
OS_trans[ov3->trans].clip;
if (clip_or & OS_CLIP_TRANSFORMED)
{
//
// This triangle needs to be zclipped.
//
return;
}
else
{
//
// The whole triangle is zclipped one way or another. We assume that
// a single triangle is not going to span both the near and far zclip
// planes...
//
return;
}
}
}
void OS_buffer_add_sprite(
OS_Buffer *ob,
float x1, // Normalised to 0.0F - 1.0F
float y1, // Normalised to 0.0F - 1.0F
float x2, // Normalised to 0.0F - 1.0F
float y2, // Normalised to 0.0F - 1.0F
float u1, float v1,
float u2, float v2,
float z,
ULONG colour,
ULONG specular,
ULONG fade)
{
SLONG i;
OS_Flert *of;
//
// Enough room in our buffer?
//
if (ob->num_indices + 6 > ob->max_indices) {OS_buffer_grow_indices(ob);}
if (ob->num_flerts + 4 > ob->max_flerts ) {OS_buffer_grow_flerts (ob);}
//
// Add four vertices.
//
for (i = 0; i < 4; i++)
{
of = &ob->flert[ob->num_flerts + i];
of->sx = ((i & 1) ? x1 : x2) * OS_screen_width;
of->sy = ((i & 2) ? y1 : y2) * OS_screen_height;
of->sz = z;
of->rhw = 0.5F;
of->colour = colour;
of->specular = specular;
of->tu1 = ((i & 1) ? u1 : u2);
of->tv1 = ((i & 2) ? v1 : v2);
of->tu2 = ((i & 1) ? u1 : u2);
of->tv2 = ((i & 2) ? v1 : v2);
}
if (fade)
{
if (fade & OS_FADE_TOP)
{
ob->flert[ob->num_flerts + 2].colour = 0x00000000;
ob->flert[ob->num_flerts + 3].colour = 0x00000000;
}
if (fade & OS_FADE_BOTTOM)
{
ob->flert[ob->num_flerts + 0].colour = 0x00000000;
ob->flert[ob->num_flerts + 1].colour = 0x00000000;
}
if (fade & OS_FADE_LEFT)
{
ob->flert[ob->num_flerts + 1].colour = 0x00000000;
ob->flert[ob->num_flerts + 3].colour = 0x00000000;
}
if (fade & OS_FADE_RIGHT)
{
ob->flert[ob->num_flerts + 0].colour = 0x00000000;
ob->flert[ob->num_flerts + 2].colour = 0x00000000;
}
}
//
// Add two triangles.
//
ob->index[ob->num_indices + 0] = ob->num_flerts + 0;
ob->index[ob->num_indices + 1] = ob->num_flerts + 1;
ob->index[ob->num_indices + 2] = ob->num_flerts + 3;
ob->index[ob->num_indices + 3] = ob->num_flerts + 0;
ob->index[ob->num_indices + 4] = ob->num_flerts + 3;
ob->index[ob->num_indices + 5] = ob->num_flerts + 2;
ob->num_indices += 6;
ob->num_flerts += 4;
}
void OS_buffer_add_sprite_rot(
OS_Buffer *ob,
float x_mid,
float y_mid,
float size, // As a percentage of the width of the screen.
float angle,
float u1, float v1,
float u2, float v2,
float z,
ULONG colour,
ULONG specular,
float tu1, float tv1,
float tu2, float tv2)
{
SLONG i;
OS_Flert *of;
float dx = sin(angle) * size;
float dy = cos(angle) * size;
float x;
float y;
x_mid *= OS_screen_width;
y_mid *= OS_screen_height;
//
// Enough room in our buffer?
//
if (ob->num_indices + 6 > ob->max_indices) {OS_buffer_grow_indices(ob);}
if (ob->num_flerts + 4 > ob->max_flerts ) {OS_buffer_grow_flerts (ob);}
//
// Add four vertices.
//
for (i = 0; i < 4; i++)
{
of = &ob->flert[ob->num_flerts + i];
x = 0.0F;
y = 0.0F;
if (i & 1)
{
x -= dx;
y -= dy;
}
else
{
x += dx;
y += dy;
}
if (i & 2)
{
x += -dy;
y += +dx;
}
else
{
x -= -dy;
y -= +dx;
}
x *= OS_screen_width;
y *= OS_screen_height * 1.33F;
x += x_mid;
y += y_mid;
of->sx = x;
of->sy = y;
of->sz = z;
of->rhw = 0.5F;
of->colour = colour;
of->specular = specular;
of->tu1 = ((i & 1) ? u1 : u2);
of->tv1 = ((i & 2) ? v1 : v2);
of->tu2 = ((i & 1) ? tu1 : tu2);
of->tv2 = ((i & 2) ? tv1 : tv2);
}
//
// Add two triangles.
//
ob->index[ob->num_indices + 0] = ob->num_flerts + 0;
ob->index[ob->num_indices + 1] = ob->num_flerts + 1;
ob->index[ob->num_indices + 2] = ob->num_flerts + 3;
ob->index[ob->num_indices + 3] = ob->num_flerts + 0;
ob->index[ob->num_indices + 4] = ob->num_flerts + 3;
ob->index[ob->num_indices + 5] = ob->num_flerts + 2;
ob->num_indices += 6;
ob->num_flerts += 4;
}
void OS_buffer_add_sprite_arbitrary(
OS_Buffer *ob,
float x1, // Normalised to 0.0F - 1.0F
float y1, // Normalised to 0.0F - 1.0F
float x2, // Normalised to 0.0F - 1.0F
float y2, // Normalised to 0.0F - 1.0F
float x3, // Normalised to 0.0F - 1.0F
float y3, // Normalised to 0.0F - 1.0F
float x4, // Normalised to 0.0F - 1.0F
float y4, // Normalised to 0.0F - 1.0F
float u1, float v1,
float u2, float v2,
float u3, float v3,
float u4, float v4,
float z ,
ULONG colour,
ULONG specular)
{
SLONG i;
float x;
float y;
float u;
float v;
OS_Flert *of;
//
// Enough room in our buffer?
//
if (ob->num_indices + 6 > ob->max_indices) {OS_buffer_grow_indices(ob);}
if (ob->num_flerts + 4 > ob->max_flerts ) {OS_buffer_grow_flerts (ob);}
//
// Add four vertices.
//
for (i = 0; i < 4; i++)
{
of = &ob->flert[ob->num_flerts + i];
switch(i)
{
case 0:
x = x1;
y = y1;
u = u1;
v = v1;
break;
case 1:
x = x2;
y = y2;
u = u2;
v = v2;
break;
case 2:
x = x3;
y = y3;
u = u3;
v = v3;
break;
case 3:
x = x4;
y = y4;
u = u4;
v = v4;
break;
default:
ASSERT(0);
break;
}
x *= OS_screen_width;
y *= OS_screen_height;
of->sx = x;
of->sy = y;
of->sz = z;
of->rhw = 0.5F;
of->colour = colour;
of->specular = specular;
of->tu1 = u;
of->tv1 = v;
of->tu2 = u;
of->tv2 = v;
}
//
// Add two triangles.
//
ob->index[ob->num_indices + 0] = ob->num_flerts + 0;
ob->index[ob->num_indices + 1] = ob->num_flerts + 1;
ob->index[ob->num_indices + 2] = ob->num_flerts + 3;
ob->index[ob->num_indices + 3] = ob->num_flerts + 0;
ob->index[ob->num_indices + 4] = ob->num_flerts + 3;
ob->index[ob->num_indices + 5] = ob->num_flerts + 2;
ob->num_indices += 6;
ob->num_flerts += 4;
}
void OS_buffer_add_line_3d(
OS_Buffer *ob,
float X1,
float Y1,
float X2,
float Y2,
float width,
float u1, float v1,
float u2, float v2,
float z1,
float z2,
ULONG colour,
ULONG specular)
{
SLONG i;
OS_Flert *of;
float dx;
float dy;
float len;
float overlen;
float x;
float y;
//
// Enough room in our buffer?
//
if (ob->num_indices + 6 > ob->max_indices) {OS_buffer_grow_indices(ob);}
if (ob->num_flerts + 4 > ob->max_flerts ) {OS_buffer_grow_flerts (ob);}
//
// The width of the line.
//
dx = X2 - X1;
dy = Y2 - Y1;
len = qdist2(fabs(dx),fabs(dy));
overlen = width * OS_screen_width / len;
dx *= overlen;
dy *= overlen;
//
// Add four vertices.
//
for (i = 0; i < 4; i++)
{
of = &ob->flert[ob->num_flerts + i];
x = 0.0F;
y = 0.0F;
if (i & 1)
{
x += -dy;
y += +dx;
}
else
{
x -= -dy;
y -= +dx;
}
if (i & 2)
{
x += X1;
y += Y1;
}
else
{
x += X2;
y += Y2;
}
of->sx = x;
of->sy = y;
of->sz = ((i & 2) ? z1 : z2);
of->rhw = 0.5F;
of->colour = colour;
of->specular = specular;
of->tu1 = ((i & 1) ? u1 : u2);
of->tv1 = ((i & 2) ? v1 : v2);
of->tu2 = ((i & 1) ? u1 : u2);
of->tv2 = ((i & 2) ? v1 : v2);
}
//
// Add two triangles.
//
ob->index[ob->num_indices + 0] = ob->num_flerts + 0;
ob->index[ob->num_indices + 1] = ob->num_flerts + 1;
ob->index[ob->num_indices + 2] = ob->num_flerts + 3;
ob->index[ob->num_indices + 3] = ob->num_flerts + 0;
ob->index[ob->num_indices + 4] = ob->num_flerts + 3;
ob->index[ob->num_indices + 5] = ob->num_flerts + 2;
ob->num_indices += 6;
ob->num_flerts += 4;
}
void OS_buffer_add_line_2d(
OS_Buffer *ob,
float x1,
float y1,
float x2,
float y2,
float width,
float u1, float v1,
float u2, float v2,
float z,
ULONG colour,
ULONG specular)
{
SLONG i;
OS_Flert *of;
float dx;
float dy;
float len;
float overlen;
float x;
float y;
//
// Enough room in our buffer?
//
if (ob->num_indices + 6 > ob->max_indices) {OS_buffer_grow_indices(ob);}
if (ob->num_flerts + 4 > ob->max_flerts ) {OS_buffer_grow_flerts (ob);}
//
// The width of the line.
//
x1 *= OS_screen_width;
y1 *= OS_screen_height;
x2 *= OS_screen_width;
y2 *= OS_screen_height;
dx = x2 - x1;
dy = y2 - y1;
len = qdist2(fabs(dx),fabs(dy));
overlen = width * OS_screen_width / len;
dx *= overlen;
dy *= overlen;
//
// Add four vertices.
//
for (i = 0; i < 4; i++)
{
of = &ob->flert[ob->num_flerts + i];
x = 0.0F;
y = 0.0F;
if (i & 1)
{
x += -dy;
y += +dx;
}
else
{
x -= -dy;
y -= +dx;
}
if (i & 2)
{
x += x1;
y += y1;
}
else
{
x += x2;
y += y2;
}
of->sx = x;
of->sy = y;
of->sz = z;
of->rhw = 0.5F;
of->colour = colour;
of->specular = specular;
of->tu1 = ((i & 1) ? u1 : u2);
of->tv1 = ((i & 2) ? v1 : v2);
of->tu2 = ((i & 1) ? u1 : u2);
of->tv2 = ((i & 2) ? v1 : v2);
}
//
// Add two triangles.
//
ob->index[ob->num_indices + 0] = ob->num_flerts + 0;
ob->index[ob->num_indices + 1] = ob->num_flerts + 1;
ob->index[ob->num_indices + 2] = ob->num_flerts + 3;
ob->index[ob->num_indices + 3] = ob->num_flerts + 0;
ob->index[ob->num_indices + 4] = ob->num_flerts + 3;
ob->index[ob->num_indices + 5] = ob->num_flerts + 2;
ob->num_indices += 6;
ob->num_flerts += 4;
}
void OS_buffer_draw(
OS_Buffer *ob,
OS_Texture *ot1,
OS_Texture *ot2,
ULONG draw)
{
LPDIRECT3DDEVICE3 d3d = OS_frame.GetD3DDevice();
if (ob->num_flerts == 0)
{
//
// Empty buffer!
//
OS_buffer_give(ob);
return;
}
if (ot1 == NULL)
{
//
// No texturing.
//
draw |= OS_DRAW_TEX_NONE;
}
else
{
//
// Make this texture the input into the pipeline.
//
d3d->SetTexture(0, ot1->ddtx);
}
if (ot2)
{
//
// Make this texture the input into the second stage of the pipeline.
//
d3d->SetTexture(1, ot2->ddtx);
}
//
// Update renderstates.
//
if (draw != OS_DRAW_NORMAL)
{
OS_change_renderstate_for_type(draw);
}
{
//
// Check that this will be okay.
//
ULONG num_passes;
if (d3d->ValidateDevice(&num_passes) != D3D_OK)
{
OS_string("Validation failed: draw = 0x%x\n", draw);
}
}
//
// Draw the triangles.
//
d3d->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST,
OS_FLERT_FORMAT,
ob->flert,
ob->num_flerts,
ob->index,
ob->num_indices,
D3DDP_DONOTUPDATEEXTENTS);
//
// Put state back to normal.
//
if (draw != OS_DRAW_NORMAL)
{
OS_undo_renderstate_type_changes();
}
//
// Returns the buffer to the free list.
//
OS_buffer_give(ob);
}
// ========================================================
//
// SOUND STUFF
//
// ========================================================
/*
void OS_sound_init()
{
if (OS_midas_ok)
{
OS_module = MIDASloadModule("Sounds\\profound.xm");
}
}
void OS_sound_start(void)
{
if (OS_module)
{
OS_module_handle = MIDASplayModule(OS_module,FALSE);
}
}
void OS_sound_volume(float vol)
{
if (OS_module && OS_module_handle)
{
SLONG volume = ftol(vol * 64.0F);
SATURATE(volume, 0, 64);
MIDASsetMusicVolume(OS_module_handle, volume);
}
}
*/
SLONG sound;
void OS_hack(void)
{
MUSIC_mode(0);
MUSIC_mode_process();
switch(rand() % 5)
{
case 0: sound = S_TUNE_COMBAT_TRAINING ; break;
case 1: sound = S_TUNE_DRIVING_TRAINING; break;
case 2: sound = S_TUNE_CLUB_START ; break;
case 3: sound = S_TUNE_CLUB_END ; break;
case 4: sound = S_TUNE_ASSAULT_TRAINING; break;
}
sound = S_CREDITS_LOOP;
OS_frame.direct_draw = the_display.lp_DD4;
OS_frame.direct_3d = the_display.lp_D3D_Device;
//
// Enumerate texture formats.
//
{
int i;
OS_Tformat *otf;
//
// Find the texture formats.
//
OS_frame.GetD3DDevice()->EnumTextureFormats(OS_texture_enumerate_pixel_formats, NULL);
//
// Set the masks and shifts for each texture format.
//
for (i = 0; i < OS_TEXTURE_FORMAT_NUMBER; i++)
{
otf = &OS_tformat[i];
if (i == OS_TEXTURE_FORMAT_8)
{
//
// We don't have to set the masks and shifts for grayscale textures.
//
continue;
}
if (otf->valid)
{
//
// Calculate the masks and shifts.
//
OS_calculate_mask_and_shift(otf->ddpf.dwRBitMask, &otf->mask_r, &otf->shift_r);
OS_calculate_mask_and_shift(otf->ddpf.dwGBitMask, &otf->mask_g, &otf->shift_g);
OS_calculate_mask_and_shift(otf->ddpf.dwBBitMask, &otf->mask_b, &otf->shift_b);
if (otf->ddpf.dwFlags & DDPF_ALPHAPIXELS)
{
OS_calculate_mask_and_shift(otf->ddpf.dwRGBAlphaBitMask, &otf->mask_a, &otf->shift_a);
}
}
}
}
//
// What's the screen res?
//
extern SLONG RealDisplayWidth;
extern SLONG RealDisplayHeight;
OS_screen_width = float(RealDisplayWidth );
OS_screen_height = float(RealDisplayHeight);
//
// Make the fast floating point to SLONG conversion macro work. It
// changes the default setting of the floating point unit to truncate
// instead of round-to-nearest.
//
ftol_init();
//
// Work out how to multi-texture
//
OS_pipeline_calculate();
//
// Time relative to the beginning of the program.
//
OS_game_start_tick_count = GetTickCount();
//
// Start the game.
//
KEY_on[KEY_ESCAPE] = 0;
MAIN_main();
//
// DO NO CLEANUP!
//
MFX_stop(0, sound);
}
void OS_sound_loop_start()
{
MFX_play_stereo(0, sound, MFX_LOOPED);
}
void OS_sound_loop_process()
{
MUSIC_mode_process();
MFX_render();
}