• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#objective-cqt誰得cocoawindowspythonrubyphpgameguibathyscaphec翻訳omegat計画中(planning stage)frameworktwittertestdombtronvb.netdirectxarduinopreviewerゲームエンジン

milligram


Commit MetaInfo

Révision95a1138b2c84848686b704a4f0939e77733b2ae2 (tree)
l'heure2011-03-17 17:12:25
Auteurberu <berupon@gmai...>
Commiterberu

Message de Log

implemented part of BitBlt function

Change Summary

Modification

--- /dev/null
+++ b/ReadImage/File.cpp
@@ -0,0 +1,60 @@
1+#include "stdafx.h"
2+#include "File.h"
3+
4+#include <io.h>
5+#include <assert.h>
6+#include <memory.h>
7+#include <stdio.h>
8+
9+#include <windows.h>
10+
11+File::File(HANDLE hFile)
12+ :
13+ hFile_(hFile)
14+{
15+}
16+
17+File::File(FILE* pFile)
18+{
19+ hFile_ = (HANDLE) _get_osfhandle(_fileno(pFile));
20+}
21+
22+bool File::Read(void* pBuffer, size_t nNumberOfBytesToRead, size_t& nNumberOfBytesRead)
23+{
24+ return ReadFile(hFile_, pBuffer, nNumberOfBytesToRead, (LPDWORD)&nNumberOfBytesRead, NULL);
25+}
26+
27+bool File::Write(const void* pBuffer, size_t nNumberOfBytesToWrite, size_t& nNumberOfBytesWritten)
28+{
29+ return WriteFile(hFile_, pBuffer, nNumberOfBytesToWrite, (LPDWORD)&nNumberOfBytesWritten, NULL);
30+}
31+
32+size_t File::Seek(long lDistanceToMove, size_t dwMoveMethod)
33+{
34+ return SetFilePointer(hFile_, lDistanceToMove, NULL, dwMoveMethod);
35+}
36+
37+size_t File::Tell() const
38+{
39+ /*
40+ -- Reference --
41+ http://nukz.net/reference/fileio/hh/winbase/filesio_3vhu.htm
42+ */
43+ return SetFilePointer(
44+ hFile_, // must have GENERIC_READ and/or GENERIC_WRITE
45+ 0, // do not move pointer
46+ NULL, // hFile is not large enough to need this pointer
47+ FILE_CURRENT
48+ ); // provides offset from current position
49+}
50+
51+size_t File::Size() const
52+{
53+ return GetFileSize(hFile_, NULL);
54+}
55+
56+bool File::Flush()
57+{
58+ return FlushFileBuffers(hFile_);
59+}
60+
--- /dev/null
+++ b/ReadImage/File.h
@@ -0,0 +1,33 @@
1+#pragma once
2+
3+#include "IFile.h"
4+
5+#include <windows.h>
6+#include <stdio.h>
7+
8+class File : public IFile
9+{
10+public:
11+ File(HANDLE hFile);
12+
13+ File(FILE* pFile);
14+
15+ bool Read(void* pBuffer, size_t nNumberOfBytesToRead, size_t& nNumberOfBytesRead);
16+
17+ bool Write(const void* pBuffer, size_t nNumberOfBytesToWrite, size_t& nNumberOfBytesWritten);
18+
19+ size_t Seek(long lDistanceToMove, size_t dwMoveMethod);
20+
21+ size_t Tell() const;
22+
23+ size_t Size() const;
24+
25+ bool Flush();
26+
27+ bool HasBuffer() const { return false; }
28+ virtual const void* GetBuffer() const { return 0; }
29+
30+private:
31+ HANDLE hFile_;
32+};
33+
--- /dev/null
+++ b/ReadImage/IFile.h
@@ -0,0 +1,33 @@
1+#pragma once
2+
3+/*!
4+
5+概要
6+ 画像の入出力用に仮想的にFileを扱えるようにする
7+
8+制限
9+ 非同期操作には対応しない
10+ 2GBまで
11+
12+備考
13+ CxImage by Davide Pizzolato (http://www.xdp.it/cximage.htm) を参考にしました。
14+
15+ InterfaceをWindowsAPIのFile関数に似せています
16+
17+*/
18+
19+class IFile
20+{
21+public:
22+ virtual bool Read(void* pBuffer, size_t nNumberOfBytesToRead, size_t& nNumberOfBytesRead) = 0;
23+ virtual bool Write(const void* pBuffer, size_t nNumberOfBytesToWrite, size_t& nNumberOfBytesWritten) = 0;
24+ virtual size_t Seek(long lDistanceToMove, size_t dwMoveMethod) = 0;
25+ virtual size_t Tell() const = 0;
26+ virtual size_t Size() const = 0;
27+ virtual bool IsEof() const { return Tell() == Size(); }
28+ virtual bool Flush() = 0;
29+
30+ virtual bool HasBuffer() const = 0;
31+ virtual const void* GetBuffer() const = 0;
32+};
33+
--- /dev/null
+++ b/ReadImage/ReadImage.cpp
@@ -0,0 +1,126 @@
1+#include "stdafx.h"
2+
3+#include "ReadImage.h"
4+#include "arrayutil.h"
5+
6+//#define TRACE printf
7+#define TRACE OutputDebugStringA
8+#include <assert.h>
9+
10+#include <windows.h>
11+
12+bool Read_BITMAPINFOHEADER(IFile& file, BITMAPINFOHEADER& bmih)
13+{
14+ size_t fileSize = file.Size();
15+ if (fileSize <= 54) {
16+ TRACE("file size <= 54 bytes.");
17+ return false;
18+ }
19+ BITMAPFILEHEADER bmpFileHeader;
20+ size_t readBytes = 0;
21+ file.Read(&bmpFileHeader, 14, readBytes);
22+ assert(readBytes == 14);
23+ if (bmpFileHeader.bfType != 19778) {
24+ TRACE("file hedear bfType != 19778");
25+ return false;
26+ }
27+
28+ file.Read(&bmih, 40, readBytes);
29+ if (readBytes != 40) {
30+ TRACE("bmih shortage.");
31+ return false;
32+ }
33+
34+ return true;
35+}
36+
37+bool ReadImageInfo_BMP(IFile& file, ImageInfo& info)
38+{
39+ BITMAPINFOHEADER bmih;
40+ if (!Read_BITMAPINFOHEADER(file, bmih)) {
41+ return false;
42+ }
43+ info.width = bmih.biWidth;
44+ info.height = bmih.biHeight;
45+ switch (bmih.biBitCount) {
46+ case 1:
47+ case 4:
48+ case 8:
49+ info.samplesPerPixel = 1;
50+ break;
51+ case 16:
52+ case 24:
53+ info.samplesPerPixel = 3;
54+ break;
55+ case 32:
56+ info.samplesPerPixel = 4;
57+ break;
58+ }
59+ info.bitsPerSample = 8;
60+ return true;
61+}
62+
63+bool ReadImageData_BMP(IFile& file, unsigned char* dest, int lineOffset, void* palettes)
64+{
65+ file.Seek(0, FILE_BEGIN);
66+ BITMAPINFOHEADER bmih;
67+ if (!Read_BITMAPINFOHEADER(file, bmih)) {
68+ return false;
69+ }
70+ size_t bmiColorsLen = 0;
71+ switch (bmih.biBitCount) {
72+ case 1:
73+ bmiColorsLen = 2;
74+ break;
75+ case 4:
76+ bmiColorsLen = 16;
77+ break;
78+ case 8:
79+ bmiColorsLen = 256;
80+ break;
81+ case 16:
82+ TRACE("16 bit BMP not supported.");
83+ return false;
84+ break;
85+ case 32:
86+ if (bmih.biCompression == BI_BITFIELDS) {
87+ bmiColorsLen = 3;
88+ }
89+ }
90+ size_t readBytes = 0;
91+ if (bmiColorsLen) {
92+ size_t needBytes = /*sizeof(RGBQUAD)*/4*bmiColorsLen;
93+ file.Read(palettes, needBytes, readBytes);
94+ if (readBytes != needBytes) {
95+ TRACE("bmiColors read failed.");
96+ return false;
97+ }
98+ }
99+ const int lineBytes = ((((bmih.biWidth * bmih.biBitCount) + 31) & ~31) >> 3);
100+ const int lineIdx = (bmih.biHeight < 0) ? 0 : (bmih.biHeight-1);
101+ OffsetPtr(dest, lineOffset * lineIdx);
102+ lineOffset *= (bmih.biHeight < 0) ? 1 : -1;
103+
104+ const size_t height = abs(bmih.biHeight);
105+ for (size_t y=0; y<height; ++y) {
106+ file.Read(dest, lineBytes, readBytes);
107+ if (readBytes != lineBytes) {
108+ TRACE("read bytes != lineBytes.");
109+ return false;
110+ }
111+ OffsetPtr(dest, lineOffset);
112+ }
113+
114+ return true;
115+}
116+
117+bool ReadImageInfo(IFile& file, ImageInfo& info)
118+{
119+ return ReadImageInfo_BMP(file, info);
120+}
121+
122+bool ReadImageData(IFile& file, unsigned char* dest, int lineOffset, void* palettes)
123+{
124+ return ReadImageData_BMP(file, dest, lineOffset, palettes);
125+}
126+
--- /dev/null
+++ b/ReadImage/ReadImage.h
@@ -0,0 +1,15 @@
1+#pragma once
2+
3+#include "IFile.h"
4+
5+struct ImageInfo
6+{
7+ size_t width;
8+ size_t height;
9+ size_t bitsPerSample;
10+ size_t samplesPerPixel;
11+};
12+
13+bool ReadImageInfo(IFile& file, ImageInfo& info);
14+bool ReadImageData(IFile& file, unsigned char* dest, int lineOffset, void* palettes);
15+
--- /dev/null
+++ b/common/winutil.cpp
@@ -0,0 +1,37 @@
1+#include "stdafx.h"
2+
3+#include "winutil.h"
4+
5+HBITMAP CreateDIB(int width, int height, int bitsPerPixel, BITMAPINFO& bmi, void*& pBits)
6+{
7+ assert(bitsPerPixel % 8 == 0);
8+ int bytesPerPixel = bitsPerPixel / 8;
9+ assert(bytesPerPixel <= 4);
10+ if (width % 4) {
11+ width += 4 - (width % 4);
12+ }
13+ assert(width % 4 == 0);
14+ BITMAPINFOHEADER& header = bmi.bmiHeader;
15+ header.biSize = sizeof(BITMAPINFOHEADER);
16+ header.biWidth = width;
17+ header.biHeight = height;
18+ header.biPlanes = 1;
19+ header.biBitCount = bitsPerPixel;
20+ header.biCompression = BI_RGB;
21+ header.biSizeImage = width * abs(height) * bytesPerPixel;
22+ header.biXPelsPerMeter = 0;
23+ header.biYPelsPerMeter = 0;
24+ header.biClrUsed = 0;
25+ header.biClrImportant = 0;
26+
27+ return ::CreateDIBSection(
28+ (HDC)0,
29+ &bmi,
30+ DIB_RGB_COLORS,
31+ &pBits,
32+ NULL,
33+ 0
34+ );
35+}
36+
37+
--- /dev/null
+++ b/common/winutil.h
@@ -0,0 +1,3 @@
1+#pragma once
2+
3+HBITMAP CreateDIB(int width, int height, int bitsPerPixel, BITMAPINFO& bmi, void*& pBits);
--- a/main_plus.cpp
+++ b/main_plus.cpp
@@ -10,6 +10,10 @@
1010 #include "mg/container.h"
1111 #include "mg/button.h"
1212
13+#include "winutil.h"
14+#include "ReadImage/File.h"
15+#include "ReadImage/ReadImage.h"
16+
1317 namespace {
1418
1519 HWND hWnd;
@@ -26,38 +30,10 @@ MG::Container mg(elements, 128);
2630 MG::Button button1;
2731 MG::Button button2;
2832
29-HBITMAP CreateDIB(int width, int height, int bitsPerPixel, BITMAPINFO& bmi, void*& pBits)
30-{
31- assert(bitsPerPixel % 8 == 0);
32- int bytesPerPixel = bitsPerPixel / 8;
33- assert(bytesPerPixel <= 4);
34- if (width % 4) {
35- width += 4 - (width % 4);
36- }
37- assert(width % 4 == 0);
38- BITMAPINFOHEADER& header = bmi.bmiHeader;
39- header.biSize = sizeof(BITMAPINFOHEADER);
40- header.biWidth = width;
41- header.biHeight = height;
42- header.biPlanes = 1;
43- header.biBitCount = bitsPerPixel;
44- header.biCompression = BI_RGB;
45- header.biSizeImage = width * abs(height) * bytesPerPixel;
46- header.biXPelsPerMeter = 0;
47- header.biYPelsPerMeter = 0;
48- header.biClrUsed = 0;
49- header.biClrImportant = 0;
50-
51- return ::CreateDIBSection(
52- (HDC)0,
53- &bmi,
54- DIB_RGB_COLORS,
55- &pBits,
56- NULL,
57- 0
58- );
59-}
60-
33+std::vector<uint8_t> imageBuffer;
34+MG::Bitmap bmpContent;
35+MG::Element pic1;
36+MG::Element pic2;
6137
6238 } // anonymous namespace
6339
@@ -115,6 +91,51 @@ void OnCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
11591 rect.h = 50;
11692 button2.rect = rect;
11793 mg.Add(button2);
94+
95+ // read content
96+ {
97+ FILE* file = fopen("test.bmp", "r");
98+ assert(file);
99+ if (!file) {
100+ return;
101+ }
102+ File fileProxy(file);
103+ ImageInfo imageInfo;
104+ ReadImageInfo(fileProxy, imageInfo);
105+ assert(imageInfo.bitsPerSample == 8 && imageInfo.samplesPerPixel == 3);
106+ imageBuffer.resize(imageInfo.width * imageInfo.height * imageInfo.samplesPerPixel);
107+ int lineOffsetBytes = imageInfo.width * imageInfo.samplesPerPixel;
108+ ReadImageData(fileProxy, &imageBuffer[0], lineOffsetBytes, 0);
109+ fclose(file);
110+ bmpContent.bitsPerPixel = imageInfo.bitsPerSample * imageInfo.samplesPerPixel;
111+ bmpContent.width = imageInfo.width;
112+ bmpContent.height = imageInfo.height;
113+ bmpContent.lineOffsetBytes = lineOffsetBytes;
114+ bmpContent.pBits = &imageBuffer[0];
115+ }
116+ rect.x = 100;
117+ rect.y = 300;
118+ pic1.rect = rect;
119+ MG::Rectangle irec;
120+ irec.x = irec.y = 0;
121+ irec.w = 400;
122+ irec.h = 400;
123+ pic1.bg.image.rect = irec;
124+ pic1.bg.image.pBitmap = &bmpContent;
125+ pic1.needsToDraw = true;
126+ mg.Add(pic1);
127+
128+ rect.x = 300;
129+ rect.y = 200;
130+ rect.w = 300;
131+ rect.h = 300;
132+ pic2.rect = rect;
133+ pic2.bg = pic1.bg;
134+ irec.x = 510;
135+ irec.y = 340;
136+ pic2.bg.image.rect = irec;
137+ pic2.needsToDraw = true;
138+ mg.Add(pic2);
118139
119140 HDC hWndDC = ::GetDC(hWnd);
120141 hMemDC = ::CreateCompatibleDC(hWndDC);
--- a/mg.vcproj
+++ b/mg.vcproj
@@ -42,7 +42,7 @@
4242 Name="VCCLCompilerTool"
4343 Optimization="0"
4444 AdditionalIncludeDirectories="./;./common/"
45- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
45+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS"
4646 MinimalRebuild="true"
4747 BasicRuntimeChecks="3"
4848 RuntimeLibrary="3"
@@ -116,7 +116,7 @@
116116 Optimization="2"
117117 EnableIntrinsicFunctions="true"
118118 AdditionalIncludeDirectories="./;./common/"
119- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
119+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS"
120120 RuntimeLibrary="2"
121121 EnableFunctionLevelLinking="true"
122122 UsePrecompiledHeader="2"
@@ -320,6 +320,38 @@
320320 RelativePath=".\common\stdint.h"
321321 >
322322 </File>
323+ <File
324+ RelativePath=".\common\winutil.cpp"
325+ >
326+ </File>
327+ <File
328+ RelativePath=".\common\winutil.h"
329+ >
330+ </File>
331+ </Filter>
332+ <Filter
333+ Name="ReadImage"
334+ >
335+ <File
336+ RelativePath=".\ReadImage\File.cpp"
337+ >
338+ </File>
339+ <File
340+ RelativePath=".\ReadImage\File.h"
341+ >
342+ </File>
343+ <File
344+ RelativePath=".\ReadImage\IFile.h"
345+ >
346+ </File>
347+ <File
348+ RelativePath=".\ReadImage\ReadImage.cpp"
349+ >
350+ </File>
351+ <File
352+ RelativePath=".\ReadImage\ReadImage.h"
353+ >
354+ </File>
323355 </Filter>
324356 <File
325357 RelativePath=".\ReadMe.txt"
--- a/mg/bitmap.cpp
+++ b/mg/bitmap.cpp
@@ -1,6 +1,7 @@
11 #include "stdafx.h"
22
33 #include "bitmap.h"
4+#include "arrayutil.h"
45
56 namespace MG {
67
@@ -14,6 +15,63 @@ Rectangle Bitmap::GetRect() const
1415 return ret;
1516 }
1617
18+void BitBlt_Src8_Dst24(
19+ const Bitmap& src, const Rectangle& srcRect,
20+ Bitmap& dst, const Rectangle& dstRect
21+ )
22+{
23+}
24+
25+void BitBlt_Src8_Dst32(
26+ const Bitmap& src, const Rectangle& srcRect,
27+ Bitmap& dst, const Rectangle& dstRect
28+ )
29+{
30+}
31+
32+void BitBlt_Src24_Dst24(
33+ const Bitmap& src, const Rectangle& srcRect,
34+ Bitmap& dst, const Rectangle& dstRect
35+ )
36+{
37+ const uint8_t* pSrc = (const uint8_t*) src.pBits;
38+ OffsetPtr(pSrc, src.lineOffsetBytes * srcRect.y);
39+ pSrc += 3 * srcRect.x;
40+
41+ uint8_t* pDst = (uint8_t*) dst.pBits;
42+ OffsetPtr(pDst, dst.lineOffsetBytes * dstRect.y);
43+ pDst += 3 * dstRect.x;
44+
45+ for (size_t y=0; y<dstRect.h; ++y) {
46+ for (size_t x=0; x<dstRect.w * 3; ++x) {
47+ pDst[x] = pSrc[x];
48+ }
49+ OffsetPtr(pSrc, src.lineOffsetBytes);
50+ OffsetPtr(pDst, dst.lineOffsetBytes);
51+ }
52+}
53+
54+void BitBlt_Src24_Dst32(
55+ const Bitmap& src, const Rectangle& srcRect,
56+ Bitmap& dst, const Rectangle& dstRect
57+ )
58+{
59+}
60+
61+void BitBlt_Src32_Dst24(
62+ const Bitmap& src, const Rectangle& srcRect,
63+ Bitmap& dst, const Rectangle& dstRect
64+ )
65+{
66+}
67+
68+void BitBlt_Src32_Dst32(
69+ const Bitmap& src, const Rectangle& srcRect,
70+ Bitmap& dst, const Rectangle& dstRect
71+ )
72+{
73+}
74+
1775 Rectangle BitBlt(
1876 const Bitmap& src, const Rectangle& srcRect,
1977 Bitmap& dst, const Rectangle& dstRect
@@ -26,24 +84,46 @@ Rectangle BitBlt(
2684 Rectangle dbr = dst.GetRect();
2785 dbr.Intersect(dstRect);
2886
87+ Rectangle sbr2 = sbr;
88+ sbr2.x = dbr.x;
89+ sbr2.y = dbr.y;
90+ dbr.Intersect(sbr2);
91+
2992 assert(dst.bitsPerPixel == 24 || dst.bitsPerPixel == 32);
30- if (src.bitsPerPixel == dst.bitsPerPixel) {
31- ;
32- }else {
33- switch (src.bitsPerPixel) {
34- case 8:
35-
93+ switch (src.bitsPerPixel) {
94+ case 8:
95+ switch (dst.bitsPerPixel) {
96+ case 24:
97+ BitBlt_Src8_Dst24(src, sbr, dst, dbr);
98+ break;
99+ case 32:
100+ BitBlt_Src8_Dst32(src, sbr, dst, dbr);
101+ break;
102+ }
103+ break;
104+ case 24:
105+ switch (dst.bitsPerPixel) {
106+ case 24:
107+ BitBlt_Src24_Dst24(src, sbr, dst, dbr);
108+ break;
109+ case 32:
110+ BitBlt_Src24_Dst32(src, sbr, dst, dbr);
36111 break;
112+ }
113+ break;
114+ case 32:
115+ switch (dst.bitsPerPixel) {
37116 case 24:
38-
117+ BitBlt_Src32_Dst24(src, sbr, dst, dbr);
39118 break;
40119 case 32:
41-
120+ BitBlt_Src32_Dst32(src, sbr, dst, dbr);
42121 break;
43122 }
123+ break;
44124 }
45125
46- return ret;
126+ return dbr;
47127 }
48128
49129
--- a/mg/bitmap.h
+++ b/mg/bitmap.h
@@ -11,8 +11,21 @@ struct Bitmap
1111 uint8_t bitsPerPixel;
1212 int lineOffsetBytes;
1313 void* pBits;
14+
15+ Rectangle GetRect() const;
16+};
1417
15- Rectangle GetRect() const;
18+struct Image {
19+ Bitmap* pBitmap;
20+ Rectangle rect;
21+
22+ Rectangle GetRect() const {
23+ if (pBitmap) {
24+ return Rectangle::Intersect(pBitmap->GetRect(), rect);
25+ }else {
26+ return rect;
27+ }
28+ }
1629 };
1730
1831 Rectangle BitBlt(
--- a/mg/element.cpp
+++ b/mg/element.cpp
@@ -10,19 +10,14 @@ void Element::Draw(int16_t offsetX, int16_t offsetY, IRenderer& renderer)
1010 Rectangle r = rect;
1111 r.x += offsetX;
1212 r.y += offsetY;
13-
13+
1414 if (bg.color) {
1515 Color c = *bg.color;
1616 renderer.FillRectangle(r, c);
1717 }
18- if (bg.pBitmap) {
19- const Bitmap& bmp = *bg.pBitmap;
20- Rectangle sr;
21- sr.x = 0;
22- sr.y = 0;
23- sr.w = bmp.width;
24- sr.h = bmp.height;
25- renderer.DrawBitmap(bmp, sr, r);
18+ if (bg.image.pBitmap) {
19+ const Bitmap& bmp = *bg.image.pBitmap;
20+ renderer.DrawBitmap(bmp, bg.image.GetRect(), r);
2621 }
2722
2823 }
--- a/mg/element.h
+++ b/mg/element.h
@@ -13,7 +13,6 @@ public:
1313 needsToDraw(false),
1414 bClickable_(false)
1515 {
16- bg.pBitmap = NULL;
1716 bg.repeatX = true;
1817 bg.repeatY = true;
1918 }
@@ -27,20 +26,20 @@ public:
2726 }
2827
2928 virtual void Draw(int16_t offsetX, int16_t offsetY, IRenderer& renderer);
30- virtual bool HitTest(int16_t x, int16_t y) const = 0;
31- virtual void OnMouseDown(int16_t x, int16_t y) = 0;
32- virtual void OnMouseUp(int16_t x, int16_t y) = 0;
33- virtual void OnMouseMove(int16_t x, int16_t y) = 0;
29+ virtual bool HitTest(int16_t x, int16_t y) const { return false; }
30+ virtual void OnMouseDown(int16_t x, int16_t y) {}
31+ virtual void OnMouseUp(int16_t x, int16_t y) {}
32+ virtual void OnMouseMove(int16_t x, int16_t y) {}
3433
3534 Rectangle rect;
3635 bool needsToDraw;
37-
36+
3837 struct Background {
3938 optional<Color> color;
40- const Bitmap* pBitmap;
39+ Image image;
4140 bool repeatX;
4241 bool repeatY;
43- }bg;
42+ } bg;
4443 protected:
4544 bool bClickable_;
4645 };
--- a/mg/rectangle.cpp
+++ b/mg/rectangle.cpp
@@ -22,10 +22,10 @@ bool Rectangle::Contains(int16_t x, int16_t y)
2222 {
2323 return
2424 1
25- && this->x <= x
26- && x < this->x + this->w
27- && this->y <= y
28- && y < this->y + this->h
25+ && Left() <= x
26+ && x < Right()
27+ && Top() <= y
28+ && y < Bottom()
2929 ;
3030 }
3131
@@ -36,7 +36,17 @@ bool Rectangle::Contains(const Rectangle& r)
3636
3737 void Rectangle::Intersect(const Rectangle& r)
3838 {
39+ int16_t left = std::max<int16_t>(Left(), r.Left());
40+ int16_t right = std::min<int16_t>(Right(), r.Right());
3941
42+ int16_t top = std::max<int16_t>(Top(), r.Top());
43+ int16_t bottom = std::min<int16_t>(Bottom(), r.Bottom());
44+
45+ x = left;
46+ w = std::max<int16_t>(0, right-left);
47+
48+ y = top;
49+ h = std::max<int16_t>(0, bottom-top);
4050 }
4151
4252 // static
--- a/mg/rectangle.h
+++ b/mg/rectangle.h
@@ -11,6 +11,11 @@ struct Rectangle
1111 uint16_t w;
1212 uint16_t h;
1313
14+ int16_t Left() const { return x; }
15+ int16_t Right() const { return x+w; }
16+ int16_t Top() const { return y; }
17+ int16_t Bottom() const { return y+h; }
18+
1419 void Offset(int16_t x, int16_t y);
1520 static Rectangle Offset(const Rectangle& r, int16_t x, int16_t y);
1621