Mercurial > mm7
diff mm7_3.cpp @ 168:ee11772d0ad2
New sky (turn on -new_sky console command)
cube textures are stored in /daata/skybox/%name%_xn.tga %name%%_xp.tga %name%_zn.tga etc
author | Nomad |
---|---|
date | Thu, 14 Feb 2013 13:58:34 +0200 |
parents | 8ab4484c22e0 |
children | d1dde383af89 |
line wrap: on
line diff
--- a/mm7_3.cpp Tue Feb 12 11:59:49 2013 +0200 +++ b/mm7_3.cpp Thu Feb 14 13:58:34 2013 +0200 @@ -6993,7 +6993,7 @@ memcpy(&array_50AC10[v28], &array_73D150[v28], sizeof(array_50AC10[v28])); ++v28; --v29; - array_50A2B0[v28 + 49].flt_20 = v30; + array_50A2B0[v28 + 49]._rhw = v30; } while ( v29 ); pFace = v46; @@ -7360,7 +7360,7 @@ v32 = 1.0 / (*(float *)(v31 * 48 + 7590236) + 0.0000001); memcpy(&array_50AC10[v31], &array_73D150[v31], sizeof(array_50AC10[v31])); ++v31; - array_50A2B0[v31 + 49].flt_20 = v32; + array_50A2B0[v31 + 49]._rhw = v32; v84 = v12->sTextureDeltaU + *(short *)(v30 - 40); array_50A2B0[v31 + 49].u = (double)v84 * v28; v33 = v12->sTextureDeltaV + *(short *)v30; @@ -7723,6 +7723,478 @@ return result; } + + +unsigned short *LoadTgaTexture(const wchar_t *filename, int *out_width = nullptr, int *out_height = nullptr) +{ + #pragma pack(push, 1) + struct TGAHeader + { + unsigned char tgaSkip; + unsigned char colourmaptype; // type of colour map 0=none, 1=has palette + unsigned char tgaType; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed + + short colourmapstart; // first colour map entry in palette + short colourmaplength; // number of colours in palette + char colourmapbits; // number of bits per palette entry 15,16,24,32 + + //unsigned char tgaDontCare2[9]; + short xstart; // image x origin + short ystart; // image y origin + + unsigned short tgaWidth; + unsigned short tgaHeight; + unsigned char tgaBPP; + + char descriptor; // image descriptor bits: 00vhaaaa + // h horizontal flip + // v vertical flip + // a alpha bits + }; + #pragma pack(pop) + + if (out_width) + *out_width = 0; + if (out_height) + *out_height = 0; + + DWORD w; + auto file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + if (file == INVALID_HANDLE_VALUE) + return nullptr; + + TGAHeader header; + ReadFile(file, &header, sizeof(header), &w, nullptr); + SetFilePointer(file, header.tgaSkip, nullptr, FILE_CURRENT); + + if (header.tgaBPP != 24 || header.tgaType != 2) + { + CloseHandle(file); + return nullptr; + } + + int imgSize = header.tgaWidth * header.tgaHeight * 3; + auto pixels = new unsigned char[imgSize]; + ReadFile(file, pixels, imgSize, &w, nullptr); + CloseHandle(file); + + if (w != imgSize) + { + delete [] pixels; + return nullptr; + } + + if (out_width) + *out_width = header.tgaWidth; + if (out_height) + *out_height = header.tgaHeight; + + auto pixels_16bit = new unsigned short[imgSize / 3]; + for (int i = 0; i < imgSize / 3; ++i) + { + pixels_16bit[i] = (pixels[i * 3] / 8 & 0x1F) | + ((pixels[i * 3 + 1] / 4 & 0x3F) << 5) | + ((pixels[i * 3 + 2] / 8 & 0x1F) << 11); + } + delete [] pixels; + return pixels_16bit; +} + +unsigned short *skybox_xn, *skybox_xp, + *skybox_yn, *skybox_yp, + *skybox_zn, *skybox_zp; +int skybox_width, skybox_height; +IDirect3DTexture2 *skybox_texture; +IDirectDrawSurface4 *skybox_surface; +bool Skybox_Initialize(const wchar_t *skybox_name) +{ + wchar_t xn_filename[1024], xp_filename[1024], + yn_filename[1024], yp_filename[1024], + zn_filename[1024], zp_filename[1024]; + swprintf(xn_filename, L"%s_xn.tga", skybox_name); swprintf(xp_filename, L"%s_xp.tga", skybox_name); + swprintf(yn_filename, L"%s_yn.tga", skybox_name); swprintf(yp_filename, L"%s_yp.tga", skybox_name); + swprintf(zn_filename, L"%s_zn.tga", skybox_name); swprintf(zp_filename, L"%s_zp.tga", skybox_name); + + int xn_width, xn_height; + skybox_xn = LoadTgaTexture(xn_filename, &xn_width, &xn_height); + if (!skybox_xn) + return false; + + int xp_width, xp_height; + skybox_xp = LoadTgaTexture(xp_filename, &xp_width, &xp_height); + if (!skybox_xp || xp_width != xn_width || xp_height != xn_height) + { + delete [] skybox_xn; + if (skybox_xp) delete [] skybox_xp; + return false; + } + + int yn_width, yn_height; + skybox_yn = LoadTgaTexture(yn_filename, &yn_width, &yn_height); + if (!skybox_yn || yn_width != xn_width || yn_height != xn_height) + { + delete [] skybox_xn; + if (skybox_xp) delete [] skybox_xp; + if (skybox_yn) delete [] skybox_yn; + return false; + } + + int yp_width, yp_height; + skybox_yp = LoadTgaTexture(yp_filename, &yp_width, &yp_height); + if (!skybox_yp || yp_width != xn_width || yp_height != xn_height) + { + delete [] skybox_xn; + if (skybox_xp) delete [] skybox_xp; + if (skybox_yn) delete [] skybox_yn; + if (skybox_yp) delete [] skybox_yp; + return false; + } + + int zn_width, zn_height; + skybox_zn = LoadTgaTexture(zn_filename, &zn_width, &zn_height); + if (!skybox_zn || zn_width != xn_width || zn_height != xn_height) + { + delete [] skybox_xn; + if (skybox_xp) delete [] skybox_xp; + if (skybox_yn) delete [] skybox_yn; + if (skybox_yp) delete [] skybox_yp; + if (skybox_zn) delete [] skybox_zn; + return false; + } + + int zp_width, zp_height; + skybox_zp = LoadTgaTexture(zp_filename, &zp_width, &zp_height); + if (!skybox_zp || zp_width != xn_width || zp_height != xn_height) + { + delete [] skybox_xn; + if (skybox_xp) delete [] skybox_xp; + if (skybox_yn) delete [] skybox_yn; + if (skybox_yp) delete [] skybox_yp; + if (skybox_zn) delete [] skybox_zn; + if (skybox_zp) delete [] skybox_zp; + return false; + } + + skybox_width = xn_width; + skybox_height = xn_height; + + + if (!pRenderer->pRenderD3D->CreateTexture(skybox_width, skybox_height, &skybox_surface, &skybox_texture, + false, false, pRenderer->uMinDeviceTextureDim)) + return false; + + return true; +} + + +struct vector +{ + float x, y, z; +}; +struct matrix +{ + float m[4][4]; +}; +void VectorNormalize(vector *v) +{ + float invmag = 1.0f / sqrtf(v->x * v->x + v->y * v->y + v->z * v->z); + v->x *= invmag; + v->y *= invmag; + v->z *= invmag; +} +void MatrixRotationAxis(matrix *pout, CONST vector *pv, float angle) +{ + memset(pout, 0, sizeof(matrix)); + pout->m[3][0] = 0; + pout->m[3][1] = 0; + pout->m[3][2] = 0; + pout->m[3][3] = 1; + + vector v; + v.x = pv->x; v.y = pv->y; v.z = pv->z; + VectorNormalize(&v); + + pout->m[0][0] = (1.0f - cos(angle)) * v.x * v.x + cos(angle); + pout->m[1][0] = (1.0f - cos(angle)) * v.x * v.y - sin(angle) * v.z; + pout->m[2][0] = (1.0f - cos(angle)) * v.x * v.z + sin(angle) * v.y; + pout->m[0][1] = (1.0f - cos(angle)) * v.y * v.x + sin(angle) * v.z; + pout->m[1][1] = (1.0f - cos(angle)) * v.y * v.y + cos(angle); + pout->m[2][1] = (1.0f - cos(angle)) * v.y * v.z - sin(angle) * v.x; + pout->m[0][2] = (1.0f - cos(angle)) * v.z * v.x - sin(angle) * v.y; + pout->m[1][2] = (1.0f - cos(angle)) * v.z * v.y + sin(angle) * v.x; + pout->m[2][2] = (1.0f - cos(angle)) * v.z * v.z + cos(angle); +} +void VectorTransform(const matrix *m, const vector *v, vector *out) +{ + out->x = m->m[0][0] * v->x + m->m[1][0] * v->y + m->m[2][0] * v->z + m->m[3][0]; + out->y = m->m[0][1] * v->x + m->m[1][1] * v->y + m->m[2][1] * v->z + m->m[3][1]; + out->z = m->m[0][2] * v->x + m->m[1][2] * v->y + m->m[2][2] * v->z + m->m[3][2]; +} + + +bool DrawSkyD3D_Skybox() +{ + static bool initialized = false, + initialization_failed = false; + if (initialization_failed) + return false; + + static int last_camera_rot_y, + last_camera_rot_x; + if (!initialized) + { + if (!Skybox_Initialize(L"data/skybox/stars")) + { + initialization_failed = true; + return false; + } + initialized = true; + + last_camera_rot_y = pParty->sRotationY + 1; // force update for the first run + last_camera_rot_x = pParty->sRotationX + 1; + } + + /* + r(y) = +cos y 0 sin y 0 +0 1 0 0 +-sin y 0 cos y 0 +0 0 0 1 + +x cos y - z sin y +y +x sin y + z cos y +1 + + + +r(x) = // should be r(right) actually +1 0 0 0 +0 cos x -sin x 0 +0 sin x cos x 0 +0 0 0 1 + + +x +y cos x + z sin x +-y sin x + z cos x +1 + + */ + + if (last_camera_rot_y == pParty->sRotationY && + last_camera_rot_x == pParty->sRotationX) + { +draw: + struct RenderVertexD3D3 v[6]; + + v[0].pos.x = pViewport->uScreenX; + v[0].pos.y = pViewport->uScreenY; + v[0].pos.z = 0.99989998; + v[0].rhw = 1; + v[0].diffuse = 0xFFFFFFFF; + v[0].specular = 0; + v[0].texcoord.x = 0; + v[0].texcoord.y = 0; + + v[1].pos.x = pViewport->uScreenX + pViewport->uScreenWidth; + v[1].pos.y = pViewport->uScreenY + pViewport->uScreenHeight; + v[1].pos.z = 0.99989998; + v[1].rhw = 1; + v[1].diffuse = 0xFFFFFFFF; + v[1].specular = 0; + v[1].texcoord.x = (float)pViewport->uScreenWidth / skybox_width; + v[1].texcoord.y = (float)pViewport->uScreenHeight / skybox_height; + + v[2].pos.x = pViewport->uScreenX + pViewport->uScreenWidth; + v[2].pos.y = pViewport->uScreenY; + v[2].pos.z = 0.99989998; + v[2].rhw = 1; + v[2].diffuse = 0xFFFFFFFF; + v[2].specular = 0; + v[2].texcoord.x = (float)pViewport->uScreenWidth / skybox_width; + v[2].texcoord.y = 0; + + memcpy(&v[3], &v[0], sizeof(*v)); + + v[4].pos.x = pViewport->uScreenX; + v[4].pos.y = pViewport->uScreenY + pViewport->uScreenHeight; + v[4].pos.z = 0.99989998; + v[4].rhw = 1; + v[4].diffuse = 0xFFFFFFFF; + v[4].specular = 0; + v[4].texcoord.x = 0; + v[4].texcoord.y = (float)pViewport->uScreenHeight / skybox_height; + + memcpy(&v[5], &v[1], sizeof(*v)); + + pRenderer->pRenderD3D->pDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); + pRenderer->pRenderD3D->pDevice->SetTexture(0, skybox_texture); + pRenderer->pRenderD3D->pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1, v, 6, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT); + //pRenderer->pRenderD3D->pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1, v + 1, 3, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT); + + return true; + } + + + DDSURFACEDESC2 desc; + desc.dwSize = sizeof(desc); + if (!pRenderer->LockSurface_DDraw4(skybox_surface, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY)) + return false; + + last_camera_rot_y = pParty->sRotationY; + last_camera_rot_x = pParty->sRotationX; + + float aspect = (float)pViewport->uScreenWidth / (float)pViewport->uScreenHeight; + float fov_x = 3.141592f * (pOutdoorCamera->uCameraFovInDegrees + 0) / 360.0f; + float fov_y = fov_x / aspect; + + float ray_dx = fov_x / (float)pViewport->uScreenWidth, + ray_dy = fov_y / (float)pViewport->uScreenHeight; + float party_angle_x = 2 * 3.141592653589 * pParty->sRotationX / 2048.0, + party_angle_y = 2 * 3.141592653589 * pParty->sRotationY / 2048.0; + for (int y = 0; y < pViewport->uScreenHeight; ++y) + for (int x = 0; x < pViewport->uScreenWidth; ++x) + { + float angle_x = party_angle_x - (y - pViewport->uScreenHeight / 2) * ray_dy; + float angle_y = party_angle_y - (x - pViewport->uScreenWidth / 2) * ray_dx; + + float _dir_x_ = 1, + _dir_y_ = 0, + _dir_z_ = 0; + + float dir_x_ = _dir_x_ * cosf(angle_y);// - _dir_z_ * sinf(angle_y); // rotation around y + //float dir_y_ = _dir_y_; + float dir_z_ = _dir_x_ * sinf(angle_y);// + _dir_z_ * cosf(angle_y); + + //float dir_x = dir_x_; // rotation around x + //float dir_y = /*dir_y_ * cosf(angle_x)*/ + dir_z_ * sinf(angle_x); + //float dir_z = /*-dir_y_ * sinf(angle_x)*/ + dir_z_ * cosf(angle_x); + + vector right; // rotate around right actually to avoid space distortion + right.x = /*dir_y * 0*/ - dir_z_ * 1; + right.y = /*dir_z_ * 0 - dir_x_ * */0; + right.z = dir_x_ * 1/* - dir_y_ * 0*/; + //VectorNormalize(&right); + + matrix rightMatrix; + MatrixRotationAxis(&rightMatrix, &right, angle_x); + + vector v1, v2; + v1.x = dir_x_; v1.y = 0; v1.z = dir_z_; + VectorTransform(&rightMatrix, &v1, &v2); + + float dir_x = v2.x, + dir_y = v2.y, + dir_z = v2.z; + + float abs_dir_x = fabsf(dir_x), + abs_dir_y = fabsf(dir_y), + abs_dir_z = fabsf(dir_z); + + unsigned short color = (0x1F << 11) | (0x1F << 5) | (5); //default to orange + if (abs_dir_x >= abs_dir_y) + { + if (abs_dir_x >= abs_dir_z) + { + if (dir_x >= 0) + { + float instersect_y = dir_y / (2.0f * dir_x); // plane equation for this side is x + 0.5 = 0 + float instersect_z = dir_z / (2.0f * dir_x); + + float u = 1.0f - (instersect_z + 0.5f), + v = 1.0f - (instersect_y + 0.5f); + + int tx = u * (skybox_width - 1), + ty = v * (skybox_height - 1); + + color = skybox_xp[ty * skybox_width + tx]; + //color = ty * 0x1F / skybox_height; + } + else + { + float instersect_y = dir_y / (2.0f * dir_x); + float instersect_z = dir_z / (2.0f * dir_x); + + float u = 1.0f - (instersect_z + 0.5f), + v = instersect_y + 0.5f; + + int tx = u * (skybox_width - 1), + ty = v * (skybox_height - 1); + + color = skybox_xn[ty * skybox_width + tx]; + //color = tx * 0x1F / skybox_height; + } + } + else if (dir_z >= 0) + goto DIR_ZP; + else + goto DIR_ZN; + } + else if (abs_dir_y >= abs_dir_z) + { + if (dir_y >= 0) + { + float instersect_x = dir_x / (2.0f * dir_y); + float instersect_z = dir_z / (2.0f * dir_y); + + float u = instersect_x + 0.5f, + v = instersect_z + 0.5f; + + int tx = u * (skybox_width - 1), + ty = v * (skybox_height - 1); + + color = skybox_yp[ty * skybox_width + tx]; + //color = tx * 0x1F / skybox_height; + } + /*else should never be seen i guess + { + __debugbreak(); + // -y + //Log::Warning(L"(%03u, %03u): -y", x, y); + }*/ + } + else if (dir_z >= 0) + { +DIR_ZP: + // +z + float instersect_x = dir_x / (2.0f * dir_z); + float instersect_y = dir_y / (2.0f * dir_z); + //float intersect_z = 0.5f; + + float u = instersect_x + 0.5f, + v = -instersect_y + 0.5f; + + int tx = u * (skybox_width - 1), + ty = v * (skybox_height - 1); + + color = skybox_zp[ty * skybox_width + tx]; + } + else + { +DIR_ZN: + // -z + float instersect_x = -dir_x / (2.0f * dir_z); + float instersect_y = -dir_y / (2.0f * dir_z); + //float intersect_z = -0.5f; + + float u = 1.0f - instersect_x - 0.5f, + v = -instersect_y + 0.5f; + + int tx = u * (skybox_width - 1), + ty = v * (skybox_height - 1); + + color = skybox_zn[ty * skybox_width + tx]; + } + + //pRenderer->pTargetSurface[(pViewport->uScreenY + y) * pRenderer->uTargetSurfacePitch + pViewport->uScreenX + x] = color; + ((unsigned __int16 *)((char *)desc.lpSurface + y * desc.lPitch))[x] = color; + } + + ErrD3D((skybox_surface)->Unlock(0)); + goto draw; +} + //----- (00479543) -------------------------------------------------------- void Render::DrawSkyD3D() { @@ -7767,6 +8239,13 @@ int v38; // [sp+158h] [bp-Ch]@1 int v39; // [sp+15Ch] [bp-8h]@4 int v40; // [sp+160h] [bp-4h]@7 + + extern bool new_sky; + if (new_sky) + { + if (DrawSkyD3D_Skybox()) + return; + } v30 = ((double)(pOutdoorCamera->int_fov_rad * pIndoorCamera->pos.z) / ((double)pOutdoorCamera->int_fov_rad + 8192.0) + pViewport->uScreenCenterY); @@ -7776,9 +8255,10 @@ _this._48607B(&stru_8019C8); _this.ptr_38->_48694B(); _this.uTileBitmapID = pOutdoor->uSky_TextureID; - _this.pTexture = (Texture *)(SLOWORD(pOutdoor->uSky_TextureID) != -1 ? (int)&pBitmaps_LOD->pTextures[SLOWORD(pOutdoor->uSky_TextureID)] : 0); + _this.pTexture = (Texture *)(SLOWORD(pOutdoor->uSky_TextureID) != -1 ? &pBitmaps_LOD->pTextures[SLOWORD(pOutdoor->uSky_TextureID)] : 0); if (pOutdoor->uSky_TextureID == -1) return; + _this.field_58 = 0; _this.uNumVertices = 4; _this.v_18.x = -stru_5C6E00->SinCos(pIndoorCamera->sRotationX - stru_5C6E00->uIntegerHalfPi + 16); @@ -7863,7 +8343,7 @@ v36 = 224 * pMiscTimer->uTotalGameTimeElapsed + (signed int)((unsigned __int64)(v36 * v18) >> 16) / 8; array_50AC10[i].vWorldViewPosition.x = pOutdoorCamera->shading_dist_mist; - array_50AC10[i].flt_20 = 1.0 / (double)(v17 / 65536); + array_50AC10[i]._rhw = 1.0 / (double)(v17 / 65536); array_50AC10[i].u = (double)v35 / (65536.0 * pBitmaps_LOD->pTextures[pOutdoor->uSky_TextureID].uTextureWidth); array_50AC10[i].v = (double)v36 / (65536.0 * pBitmaps_LOD->pTextures[pOutdoor->uSky_TextureID].uTextureWidth); } @@ -7871,22 +8351,22 @@ float t = (GetTickCount() % 96000) / 96000.0f; array_50AC10[0].vWorldViewPosition.x = pOutdoorCamera->shading_dist_mist; - array_50AC10[0].flt_20 = 1; + array_50AC10[0]._rhw = 1; array_50AC10[0].u = 0; array_50AC10[0].v = 0 + t; array_50AC10[1].vWorldViewPosition.x = pOutdoorCamera->shading_dist_mist; - array_50AC10[1].flt_20 = 1; + array_50AC10[1]._rhw = 1; array_50AC10[1].u = 0; array_50AC10[1].v = 1 + t; array_50AC10[2].vWorldViewPosition.x = pOutdoorCamera->shading_dist_mist; - array_50AC10[2].flt_20 = 1; + array_50AC10[2]._rhw = 1; array_50AC10[2].u = 1; array_50AC10[2].v = 0 + t; array_50AC10[3].vWorldViewPosition.x = pOutdoorCamera->shading_dist_mist; - array_50AC10[3].flt_20 = 1; + array_50AC10[3]._rhw = 1; array_50AC10[3].u = 1; array_50AC10[3].v = 1 + t; pRenderer->DrawStrip(_this.uNumVertices, &_this, @@ -9294,7 +9774,7 @@ v5 = uNumVertices; do { - v6 = v1 * array_507D30[v4].flt_20; + v6 = v1 * array_507D30[v4]._rhw; v7 = v6 * array_507D30[v4].vWorldViewPosition.y; memcpy(&array_50AC10[v4], &array_507D30[v4], sizeof(array_50AC10[v4])); array_50AC10[v4].vWorldViewProjX = v2 - v7; @@ -18512,7 +18992,7 @@ double v2; // st7@1 v1 = 1.0 / (v->vWorldViewPosition.x + 0.0000001); - v->flt_20 = v1; + v->_rhw = v1; v2 = v1 * (double)pOutdoorCamera->int_fov_rad; v->vWorldViewProjX = (double)pViewport->uScreenCenterX - v2 * v->vWorldViewPosition.y; v->vWorldViewProjY = (double)pViewport->uScreenCenterY - v2 * v->vWorldViewPosition.z;