int PatBlt_16bpp(HDC hdc, int nXLeft, int nYLeft, int nWidth, int nHeight, int rop) { if (ClipCoords(hdc, &nXLeft, &nYLeft, &nWidth, &nHeight, NULL, NULL) == 0) return 0; InvalidateRegion(hdc, nXLeft, nYLeft, nWidth, nHeight); switch (rop) { case PATCOPY: return BitBlt_PATCOPY_16bpp(hdc, nXLeft, nYLeft, nWidth, nHeight); break; case PATINVERT: return BitBlt_PATINVERT_16bpp(hdc, nXLeft, nYLeft, nWidth, nHeight); break; case DSTINVERT: return BitBlt_DSTINVERT_16bpp(hdc, nXLeft, nYLeft, nWidth, nHeight); break; case BLACKNESS: return BitBlt_BLACKNESS_16bpp(hdc, nXLeft, nYLeft, nWidth, nHeight); break; case WHITENESS: return BitBlt_WHITENESS_16bpp(hdc, nXLeft, nYLeft, nWidth, nHeight); break; } printf("PatBlt: unknown rop: 0x%08X", rop); return 1; }
int FillRect_16bpp(HDC hdc, HRECT rect, HBRUSH hbr) { int x, y; uint16 *dstp; int nXDest, nYDest; int nWidth, nHeight; uint16 color16; RectToCRgn(rect, &nXDest, &nYDest, &nWidth, &nHeight); if (ClipCoords(hdc, &nXDest, &nYDest, &nWidth, &nHeight, NULL, NULL) == 0) return 0; color16 = gdi_get_color_16bpp(hdc, hbr->color); for (y = 0; y < nHeight; y++) { dstp = (uint16*) gdi_get_bitmap_pointer(hdc, nXDest, nYDest + y); if (dstp != 0) { for (x = 0; x < nWidth; x++) { *dstp = color16; dstp++; } } } InvalidateRegion(hdc, nXDest, nYDest, nWidth, nHeight); return 0; }
int FillRect_32bpp(HDC hdc, HRECT rect, HBRUSH hbr) { int x, y; uint8 *dstp; char r, g, b; int nXDest, nYDest; int nWidth, nHeight; RectToCRgn(rect, &nXDest, &nYDest, &nWidth, &nHeight); if (ClipCoords(hdc, &nXDest, &nYDest, &nWidth, &nHeight, NULL, NULL) == 0) return 0; GetRGB(r, g, b, hbr->color); for (y = 0; y < nHeight; y++) { dstp = gdi_get_bitmap_pointer(hdc, nXDest, nYDest + y); if (dstp != 0) { for (x = 0; x < nWidth; x++) { *dstp = b; dstp++; *dstp = g; dstp++; *dstp = r; #ifdef USE_ALPHA dstp++; *dstp = 0xFF; dstp++; #else dstp += 2; #endif } } } InvalidateRegion(hdc, nXDest, nYDest, nWidth, nHeight); return 0; }
int FillRect_16bpp(HDC hdc, HRECT rect, HBRUSH hbr) { int x, y; char *dstp; char r, g, b; int nXDest, nYDest; int nWidth, nHeight; uint16 *dstp16; uint16 color16; RectToCRgn(rect, &nXDest, &nYDest, &nWidth, &nHeight); if (ClipCoords(hdc, &nXDest, &nYDest, &nWidth, &nHeight, NULL, NULL) == 0) return 0; GetRGB(r, g, b, hbr->color); RGB_888_565(r, g, b); color16 = RGB16(r, g, b); for (y = 0; y < nHeight; y++) { dstp = gdi_get_bitmap_pointer(hdc, nXDest, nYDest + y); if (dstp != 0) { for (x = 0; x < nWidth; x++) { dstp16 = (uint16*) dstp; *dstp16 = color16; dstp += 2; } } } InvalidateRegion(hdc, nXDest, nYDest, nWidth, nHeight); return 0; }
ClipCoords TransformUnit::ViewToClip(const ViewCoords& coords) { Vec4<float> coords4(coords.x, coords.y, coords.z, 1.0f); Mat4x4<float> projection_matrix(gstate.projMatrix); return ClipCoords(projection_matrix * coords4); }
VertexData TransformUnit::ReadVertex(VertexReader& vreader) { VertexData vertex; float pos[3]; // VertexDecoder normally scales z, but we want it unscaled. vreader.ReadPosThroughZ16(pos); if (!gstate.isModeClear() && gstate.isTextureMapEnabled() && vreader.hasUV()) { float uv[2]; vreader.ReadUV(uv); vertex.texturecoords = Vec2<float>(uv[0], uv[1]); } if (vreader.hasNormal()) { float normal[3]; vreader.ReadNrm(normal); vertex.normal = Vec3<float>(normal[0], normal[1], normal[2]); if (gstate.areNormalsReversed()) vertex.normal = -vertex.normal; } if (vertTypeIsSkinningEnabled(gstate.vertType) && !gstate.isModeThrough()) { float W[8] = { 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f }; vreader.ReadWeights(W); Vec3<float> tmppos(0.f, 0.f, 0.f); Vec3<float> tmpnrm(0.f, 0.f, 0.f); for (int i = 0; i < vertTypeGetNumBoneWeights(gstate.vertType); ++i) { Mat3x3<float> bone(&gstate.boneMatrix[12*i]); tmppos += (bone * ModelCoords(pos[0], pos[1], pos[2]) + Vec3<float>(gstate.boneMatrix[12*i+9], gstate.boneMatrix[12*i+10], gstate.boneMatrix[12*i+11])) * W[i]; if (vreader.hasNormal()) tmpnrm += (bone * vertex.normal) * W[i]; } pos[0] = tmppos.x; pos[1] = tmppos.y; pos[2] = tmppos.z; if (vreader.hasNormal()) vertex.normal = tmpnrm; } if (vreader.hasColor0()) { float col[4]; vreader.ReadColor0(col); vertex.color0 = Vec4<int>(col[0]*255, col[1]*255, col[2]*255, col[3]*255); } else { vertex.color0 = Vec4<int>(gstate.getMaterialAmbientR(), gstate.getMaterialAmbientG(), gstate.getMaterialAmbientB(), gstate.getMaterialAmbientA()); } if (vreader.hasColor1()) { float col[3]; vreader.ReadColor1(col); vertex.color1 = Vec3<int>(col[0]*255, col[1]*255, col[2]*255); } else { vertex.color1 = Vec3<int>(0, 0, 0); } if (!gstate.isModeThrough()) { vertex.modelpos = ModelCoords(pos[0], pos[1], pos[2]); vertex.worldpos = WorldCoords(TransformUnit::ModelToWorld(vertex.modelpos)); ModelCoords viewpos = TransformUnit::WorldToView(vertex.worldpos); vertex.clippos = ClipCoords(TransformUnit::ViewToClip(viewpos)); if (gstate.isFogEnabled()) { float fog_end = getFloat24(gstate.fog1); float fog_slope = getFloat24(gstate.fog2); // Same fixup as in ShaderManagerGLES.cpp if (my_isnanorinf(fog_end)) { // Not really sure what a sensible value might be, but let's try 64k. fog_end = std::signbit(fog_end) ? -65535.0f : 65535.0f; } if (my_isnanorinf(fog_slope)) { fog_slope = std::signbit(fog_slope) ? -65535.0f : 65535.0f; } vertex.fogdepth = (viewpos.z + fog_end) * fog_slope; } else { vertex.fogdepth = 1.0f; } vertex.screenpos = ClipToScreenInternal(vertex.clippos, &outside_range_flag); if (vreader.hasNormal()) { vertex.worldnormal = TransformUnit::ModelToWorldNormal(vertex.normal); // TODO: Isn't there a flag that controls whether to normalize the normal? vertex.worldnormal /= vertex.worldnormal.Length(); } else { vertex.worldnormal = Vec3<float>(0.0f, 0.0f, 1.0f); } Lighting::Process(vertex, vreader.hasColor0()); } else { vertex.screenpos.x = (int)(pos[0] * 16) + gstate.getOffsetX16(); vertex.screenpos.y = (int)(pos[1] * 16) + gstate.getOffsetY16(); vertex.screenpos.z = pos[2]; vertex.clippos.w = 1.f; vertex.fogdepth = 1.f; } return vertex; }
static VertexData ReadVertex(VertexReader& vreader) { VertexData vertex; float pos[3]; // VertexDecoder normally scales z, but we want it unscaled. vreader.ReadPosZ16(pos); if (!gstate.isModeClear() && gstate.isTextureMapEnabled() && vreader.hasUV()) { float uv[2]; vreader.ReadUV(uv); vertex.texturecoords = Vec2<float>(uv[0], uv[1]); } if (vreader.hasNormal()) { float normal[3]; vreader.ReadNrm(normal); vertex.normal = Vec3<float>(normal[0], normal[1], normal[2]); if (gstate.areNormalsReversed()) vertex.normal = -vertex.normal; } if (gstate.isSkinningEnabled() && !gstate.isModeThrough()) { float W[8] = { 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f }; vreader.ReadWeights(W); Vec3<float> tmppos(0.f, 0.f, 0.f); Vec3<float> tmpnrm(0.f, 0.f, 0.f); for (int i = 0; i < gstate.getNumBoneWeights(); ++i) { Mat3x3<float> bone(&gstate.boneMatrix[12*i]); tmppos += W[i] * (bone * ModelCoords(pos[0], pos[1], pos[2]) + Vec3<float>(gstate.boneMatrix[12*i+9], gstate.boneMatrix[12*i+10], gstate.boneMatrix[12*i+11])); if (vreader.hasNormal()) tmpnrm += W[i] * (bone * vertex.normal); } pos[0] = tmppos.x; pos[1] = tmppos.y; pos[2] = tmppos.z; if (vreader.hasNormal()) vertex.normal = tmpnrm; } if (vreader.hasColor0()) { float col[4]; vreader.ReadColor0(col); vertex.color0 = Vec4<int>(col[0]*255, col[1]*255, col[2]*255, col[3]*255); } else { vertex.color0 = Vec4<int>(gstate.getMaterialAmbientR(), gstate.getMaterialAmbientG(), gstate.getMaterialAmbientB(), gstate.getMaterialAmbientA()); } if (vreader.hasColor1()) { float col[3]; vreader.ReadColor1(col); vertex.color1 = Vec3<int>(col[0]*255, col[1]*255, col[2]*255); } else { vertex.color1 = Vec3<int>(0, 0, 0); } if (!gstate.isModeThrough()) { vertex.modelpos = ModelCoords(pos[0], pos[1], pos[2]); vertex.worldpos = WorldCoords(TransformUnit::ModelToWorld(vertex.modelpos)); vertex.clippos = ClipCoords(TransformUnit::ViewToClip(TransformUnit::WorldToView(vertex.worldpos))); vertex.screenpos = ClipToScreenInternal(vertex.clippos); if (vreader.hasNormal()) { vertex.worldnormal = TransformUnit::ModelToWorld(vertex.normal) - Vec3<float>(gstate.worldMatrix[9], gstate.worldMatrix[10], gstate.worldMatrix[11]); vertex.worldnormal /= vertex.worldnormal.Length(); // TODO: Shouldn't be necessary.. } Lighting::Process(vertex); } else { vertex.screenpos.x = (u32)pos[0] * 16 + gstate.getOffsetX16(); vertex.screenpos.y = (u32)pos[1] * 16 + gstate.getOffsetY16(); vertex.screenpos.z = pos[2]; vertex.clippos.w = 1.f; } return vertex; }
void ProcessRect(const VertexData& v0, const VertexData& v1) { if (!gstate.isModeThrough()) { VertexData buf[4]; buf[0].clippos = ClipCoords(v0.clippos.x, v0.clippos.y, v1.clippos.z, v1.clippos.w); buf[0].texturecoords = v0.texturecoords; buf[1].clippos = ClipCoords(v0.clippos.x, v1.clippos.y, v1.clippos.z, v1.clippos.w); buf[1].texturecoords = Vec2<float>(v0.texturecoords.x, v1.texturecoords.y); buf[2].clippos = ClipCoords(v1.clippos.x, v0.clippos.y, v1.clippos.z, v1.clippos.w); buf[2].texturecoords = Vec2<float>(v1.texturecoords.x, v0.texturecoords.y); buf[3] = v1; // Color and depth values of second vertex are used for the whole rectangle buf[0].color0 = buf[1].color0 = buf[2].color0 = buf[3].color0; buf[0].color1 = buf[1].color1 = buf[2].color1 = buf[3].color1; buf[0].fogdepth = buf[1].fogdepth = buf[2].fogdepth = buf[3].fogdepth; VertexData* topleft = &buf[0]; VertexData* topright = &buf[1]; VertexData* bottomleft = &buf[2]; VertexData* bottomright = &buf[3]; for (int i = 0; i < 4; ++i) { if (buf[i].clippos.x < topleft->clippos.x && buf[i].clippos.y < topleft->clippos.y) topleft = &buf[i]; if (buf[i].clippos.x > topright->clippos.x && buf[i].clippos.y < topright->clippos.y) topright = &buf[i]; if (buf[i].clippos.x < bottomleft->clippos.x && buf[i].clippos.y > bottomleft->clippos.y) bottomleft = &buf[i]; if (buf[i].clippos.x > bottomright->clippos.x && buf[i].clippos.y > bottomright->clippos.y) bottomright = &buf[i]; } // Four triangles to do backfaces as well. Two of them will get backface culled. ProcessTriangle(*topleft, *topright, *bottomright, buf[3]); ProcessTriangle(*bottomright, *topright, *topleft, buf[3]); ProcessTriangle(*bottomright, *bottomleft, *topleft, buf[3]); ProcessTriangle(*topleft, *bottomleft, *bottomright, buf[3]); } else { // through mode handling VertexData buf[4]; buf[0].screenpos = ScreenCoords(v0.screenpos.x, v0.screenpos.y, v1.screenpos.z); buf[0].texturecoords = v0.texturecoords; buf[1].screenpos = ScreenCoords(v0.screenpos.x, v1.screenpos.y, v1.screenpos.z); buf[1].texturecoords = Vec2<float>(v0.texturecoords.x, v1.texturecoords.y); buf[2].screenpos = ScreenCoords(v1.screenpos.x, v0.screenpos.y, v1.screenpos.z); buf[2].texturecoords = Vec2<float>(v1.texturecoords.x, v0.texturecoords.y); buf[3] = v1; // Color and depth values of second vertex are used for the whole rectangle buf[0].color0 = buf[1].color0 = buf[2].color0 = buf[3].color0; buf[0].color1 = buf[1].color1 = buf[2].color1 = buf[3].color1; buf[0].clippos.w = buf[1].clippos.w = buf[2].clippos.w = buf[3].clippos.w = 1.0f; buf[0].fogdepth = buf[1].fogdepth = buf[2].fogdepth = buf[3].fogdepth = 1.0f; VertexData* topleft = &buf[0]; VertexData* topright = &buf[1]; VertexData* bottomleft = &buf[2]; VertexData* bottomright = &buf[3]; // Um. Why is this stuff needed? for (int i = 0; i < 4; ++i) { if (buf[i].screenpos.x < topleft->screenpos.x && buf[i].screenpos.y < topleft->screenpos.y) topleft = &buf[i]; if (buf[i].screenpos.x > topright->screenpos.x && buf[i].screenpos.y < topright->screenpos.y) topright = &buf[i]; if (buf[i].screenpos.x < bottomleft->screenpos.x && buf[i].screenpos.y > bottomleft->screenpos.y) bottomleft = &buf[i]; if (buf[i].screenpos.x > bottomright->screenpos.x && buf[i].screenpos.y > bottomright->screenpos.y) bottomright = &buf[i]; } RotateUVThrough(v0, v1, *topright, *bottomleft); if (gstate.isModeClear()) { Rasterizer::ClearRectangle(v0, v1); } else { // Four triangles to do backfaces as well. Two of them will get backface culled. Rasterizer::DrawTriangle(*topleft, *topright, *bottomright); Rasterizer::DrawTriangle(*bottomright, *topright, *topleft); Rasterizer::DrawTriangle(*bottomright, *bottomleft, *topleft); Rasterizer::DrawTriangle(*topleft, *bottomleft, *bottomright); } } }
void ProcessQuad(const VertexData& v0, const VertexData& v1) { if (!gstate.isModeThrough()) { VertexData buf[4]; buf[0].clippos = ClipCoords(v0.clippos.x, v0.clippos.y, v1.clippos.z, v1.clippos.w); buf[0].texturecoords = v0.texturecoords; buf[1].clippos = ClipCoords(v0.clippos.x, v1.clippos.y, v1.clippos.z, v1.clippos.w); buf[1].texturecoords = Vec2<float>(v0.texturecoords.x, v1.texturecoords.y); buf[2].clippos = ClipCoords(v1.clippos.x, v0.clippos.y, v1.clippos.z, v1.clippos.w); buf[2].texturecoords = Vec2<float>(v1.texturecoords.x, v0.texturecoords.y); buf[3] = v1; // Color and depth values of second vertex are used for the whole rectangle buf[0].color0 = buf[1].color0 = buf[2].color0 = buf[3].color0; buf[0].color1 = buf[1].color1 = buf[2].color1 = buf[3].color1; VertexData* topleft = &buf[0]; VertexData* topright = &buf[1]; VertexData* bottomleft = &buf[2]; VertexData* bottomright = &buf[3]; for (int i = 0; i < 4; ++i) { if (buf[i].clippos.x < topleft->clippos.x && buf[i].clippos.y < topleft->clippos.y) topleft = &buf[i]; if (buf[i].clippos.x > topright->clippos.x && buf[i].clippos.y < topright->clippos.y) topright = &buf[i]; if (buf[i].clippos.x < bottomleft->clippos.x && buf[i].clippos.y > bottomleft->clippos.y) bottomleft = &buf[i]; if (buf[i].clippos.x > bottomright->clippos.x && buf[i].clippos.y > bottomright->clippos.y) bottomright = &buf[i]; } ProcessTriangle(*topleft, *topright, *bottomright); ProcessTriangle(*bottomright, *topright, *topleft); ProcessTriangle(*bottomright, *bottomleft, *topleft); ProcessTriangle(*topleft, *bottomleft, *bottomright); } else { // through mode handling VertexData buf[4]; buf[0].screenpos = ScreenCoords(v0.screenpos.x, v0.screenpos.y, v1.screenpos.z); buf[0].texturecoords = v0.texturecoords; buf[1].screenpos = ScreenCoords(v0.screenpos.x, v1.screenpos.y, v1.screenpos.z); buf[1].texturecoords = Vec2<float>(v0.texturecoords.x, v1.texturecoords.y); buf[2].screenpos = ScreenCoords(v1.screenpos.x, v0.screenpos.y, v1.screenpos.z); buf[2].texturecoords = Vec2<float>(v1.texturecoords.x, v0.texturecoords.y); buf[3] = v1; // Color and depth values of second vertex are used for the whole rectangle buf[0].color0 = buf[1].color0 = buf[2].color0 = buf[3].color0; buf[0].color1 = buf[1].color1 = buf[2].color1 = buf[3].color1; buf[0].clippos.w = buf[1].clippos.w = buf[2].clippos.w = buf[3].clippos.w = 1.0f; VertexData* topleft = &buf[0]; VertexData* topright = &buf[1]; VertexData* bottomleft = &buf[2]; VertexData* bottomright = &buf[3]; for (int i = 0; i < 4; ++i) { if (buf[i].screenpos.x < topleft->screenpos.x && buf[i].screenpos.y < topleft->screenpos.y) topleft = &buf[i]; if (buf[i].screenpos.x > topright->screenpos.x && buf[i].screenpos.y < topright->screenpos.y) topright = &buf[i]; if (buf[i].screenpos.x < bottomleft->screenpos.x && buf[i].screenpos.y > bottomleft->screenpos.y) bottomleft = &buf[i]; if (buf[i].screenpos.x > bottomright->screenpos.x && buf[i].screenpos.y > bottomright->screenpos.y) bottomright = &buf[i]; } Rasterizer::DrawTriangle(*topleft, *topright, *bottomright); Rasterizer::DrawTriangle(*bottomright, *topright, *topleft); Rasterizer::DrawTriangle(*bottomright, *bottomleft, *topleft); Rasterizer::DrawTriangle(*topleft, *bottomleft, *bottomright); } }
int BitBlt_16bpp(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, int rop) { if (hdcSrc != NULL) { if (ClipCoords(hdcDest, &nXDest, &nYDest, &nWidth, &nHeight, &nXSrc, &nYSrc) == 0) return 0; } else { if (ClipCoords(hdcDest, &nXDest, &nYDest, &nWidth, &nHeight, NULL, NULL) == 0) return 0; } InvalidateRegion(hdcDest, nXDest, nYDest, nWidth, nHeight); switch (rop) { case BLACKNESS: return BitBlt_BLACKNESS_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight); break; case WHITENESS: return BitBlt_WHITENESS_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight); break; case SRCCOPY: return BitBlt_SRCCOPY_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; case SPna: return BitBlt_SPna_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; case DSna: return BitBlt_DSna_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; case DSPDxax: return BitBlt_DSPDxax_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; case NOTSRCCOPY: return BitBlt_NOTSRCCOPY_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; case DSTINVERT: return BitBlt_DSTINVERT_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight); break; case SRCERASE: return BitBlt_SRCERASE_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; case NOTSRCERASE: return BitBlt_NOTSRCERASE_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; case SRCINVERT: return BitBlt_SRCINVERT_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; case SRCAND: return BitBlt_SRCAND_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; case SRCPAINT: return BitBlt_SRCPAINT_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; case MERGECOPY: return BitBlt_MERGECOPY_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; case MERGEPAINT: return BitBlt_MERGEPAINT_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; case PATCOPY: return BitBlt_PATCOPY_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight); break; case PATINVERT: return BitBlt_PATINVERT_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight); break; case PATPAINT: return BitBlt_PATPAINT_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; } printf("BitBlt: unknown rop: 0x%08X\n", rop); return 1; }