From c095ed37da6254e8161471d3374674f115d3445f Mon Sep 17 00:00:00 2001 From: unodgs Date: Sat, 2 Jul 2011 21:23:17 +0000 Subject: [PATCH] Rainbow: WinGL.. git-svn-id: svn://ultimatepp.org/upp/trunk@3596 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- rainbow/Paint/Paint.upp | 2 - rainbow/PaintGl/PaintGl.upp | 11 + rainbow/PaintGl/init | 6 + rainbow/PaintGl/main.cpp | 78 +++++ rainbow/WinGl/After.h | 21 +- rainbow/WinGl/ChSysInit.cpp | 16 + rainbow/WinGl/Clip.cpp | 241 ++++++++++++++ rainbow/WinGl/Ctrl.h | 20 +- rainbow/WinGl/Dnd.cpp | 40 +++ rainbow/WinGl/Draw.cpp | 8 +- rainbow/WinGl/DrawOp.cpp | 412 +++++++++++++++++++++++ rainbow/WinGl/DrawText.cpp | 273 +++++++++++++++ rainbow/WinGl/Event.cpp | 19 +- rainbow/WinGl/Image.cpp | 125 +++++++ rainbow/WinGl/Proc.cpp | 26 +- rainbow/WinGl/Top.cpp | 82 +++++ rainbow/WinGl/Top.h | 2 +- rainbow/WinGl/Util.cpp | 20 ++ rainbow/WinGl/Win.cpp | 37 ++- rainbow/WinGl/WinGl.h | 10 +- rainbow/WinGl/WinGl.upp | 12 + rainbow/WinGl/Wnd.cpp | 418 +++++++++++++++++++++++ rainbow/WinGl/tahoma14.fnt | 643 ++++++++++++++++++++++++++++++++++++ rainbow/WinGl/tahoma14.png | Bin 0 -> 9684 bytes rainbow/WinGl/tahoma14b.fnt | 537 ++++++++++++++++++++++++++++++ rainbow/WinGl/tahoma14b.png | Bin 0 -> 10325 bytes 26 files changed, 2995 insertions(+), 64 deletions(-) create mode 100644 rainbow/PaintGl/PaintGl.upp create mode 100644 rainbow/PaintGl/init create mode 100644 rainbow/PaintGl/main.cpp create mode 100644 rainbow/WinGl/ChSysInit.cpp create mode 100644 rainbow/WinGl/Clip.cpp create mode 100644 rainbow/WinGl/Dnd.cpp create mode 100644 rainbow/WinGl/DrawOp.cpp create mode 100644 rainbow/WinGl/DrawText.cpp create mode 100644 rainbow/WinGl/Image.cpp create mode 100644 rainbow/WinGl/Top.cpp create mode 100644 rainbow/WinGl/Util.cpp create mode 100644 rainbow/WinGl/Wnd.cpp create mode 100644 rainbow/WinGl/tahoma14.fnt create mode 100644 rainbow/WinGl/tahoma14.png create mode 100644 rainbow/WinGl/tahoma14b.fnt create mode 100644 rainbow/WinGl/tahoma14b.png diff --git a/rainbow/Paint/Paint.upp b/rainbow/Paint/Paint.upp index a6d5209e2..25d0f2fb1 100644 --- a/rainbow/Paint/Paint.upp +++ b/rainbow/Paint/Paint.upp @@ -5,8 +5,6 @@ uses Framebuffer, RichEdit; -uses(WINGL) WinGl; - uses(WINFB) WinFb; uses(LINUXFB) LinuxFb; diff --git a/rainbow/PaintGl/PaintGl.upp b/rainbow/PaintGl/PaintGl.upp new file mode 100644 index 000000000..b42963ead --- /dev/null +++ b/rainbow/PaintGl/PaintGl.upp @@ -0,0 +1,11 @@ +uses + CtrlLib, + Painter, + WinGl; + +file + main.cpp; + +mainconfig + "" = "GUI WINGL"; + diff --git a/rainbow/PaintGl/init b/rainbow/PaintGl/init new file mode 100644 index 000000000..84aafd54a --- /dev/null +++ b/rainbow/PaintGl/init @@ -0,0 +1,6 @@ +#ifndef _PaintGl_icpp_init_stub +#define _PaintGl_icpp_init_stub +#include "CtrlLib/init" +#include "Painter/init" +#include "WinGl/init" +#endif diff --git a/rainbow/PaintGl/main.cpp b/rainbow/PaintGl/main.cpp new file mode 100644 index 000000000..fac25ff83 --- /dev/null +++ b/rainbow/PaintGl/main.cpp @@ -0,0 +1,78 @@ +#include +#include + +using namespace Upp; + +struct App : public Ctrl { + EditString x; + ArrayCtrl a, b; + DropList dl; + + StaticRect popup; + + void Paint(Draw& w) + { + Size sz = GetSize(); + DDUMP(sz); + w.DrawRect(0, 0, sz.cx, sz.cy, SWhite); + w.DrawRect(10, 10, 30, 30, SRed); + w.DrawLine(45, 45, 80, 120, 4, Blue); + w.DrawLine(80, 90, 400, 0, PEN_DASHDOT); + w.DrawEllipse(200, 200, 50, 100, Green); + w.DrawImage(200, 10, CtrlImg::HandCursor()); + const char *text = "This text is centered"; + Size tsz = GetTextSize(text, Arial(25).Bold()); + w.DrawText((sz.cx - tsz.cx) / 2, (sz.cy - tsz.cy) / 2, text, Arial(27).Bold(), SBlue); + w.Clipoff(200, 50, 95, 100); + w.DrawText(0, 80, "CLIPPED", Roman(25)); + w.End(); + } + + void LeftDown(Point p, dword) + { + popup.SetRect(p.x, p.y, 100, 400); + } + + void InitArray(ArrayCtrl& a) + { + a.AddColumn("first"); + a.AddColumn("second"); + for(int i = 0; i < 100; i++) + a.Add(i, FormatIntRoman(i)); + } + + App() + { + x <<= "Hello world!"; + Add(x.LeftPos(100, 100).TopPos(500, 20)); + Add(a.LeftPos(300, 150).TopPos(10, 300)); + InitArray(a); + InitArray(b); + popup.SetFrame(BlackFrame()); + popup.Add(b.HSizePos(10, 10).VSizePos(10, 10)); + popup.SetRect(800, 100, 100, 400); + + Add(dl.LeftPos(10, 300).TopPos(10, 30)); + for(int i = 0; i < 100; i++) + dl.Add(i); +// Sizeable(); + } +}; + +#define EDITOR 0 + +GUI_APP_MAIN +{ +#if EDITOR + RichEditWithToolBar app; +#else + App app; +#endif + ChStdSkin(); + Ctrl::SetDesktop(app); + app.SetFocus(); +#if !EDITOR + app.popup.PopUp(); +#endif + Ctrl::EventLoop(); +} diff --git a/rainbow/WinGl/After.h b/rainbow/WinGl/After.h index 69078457a..ce764d682 100644 --- a/rainbow/WinGl/After.h +++ b/rainbow/WinGl/After.h @@ -11,12 +11,14 @@ public: ~ViewDraw() {} }; +class DHCtrl : Ctrl {}; + void InitGl(); Vector& coreCmdLine__(); Vector SplitCmdLine__(const char *cmd); -void FBInit(HINSTANCE hInstance); +int GlInit(HINSTANCE hInstance); #define GUI_APP_MAIN \ void GuiMainFn_();\ @@ -25,12 +27,17 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, int nCmdSh { \ UPP::coreCmdLine__() = UPP::SplitCmdLine__(UPP::FromSystemCharset(lpCmdLine)); \ UPP::AppInitEnvironment__(); \ - UPP::GlInit(hInstance); \ - GuiMainFn_(); \ - UPP::Ctrl::CloseTopCtrls(); \ - UPP::UsrLog("---------- About to delete this log of WinGL..."); \ - UPP::DeleteUsrLog(); \ - return UPP::GetExitCode(); \ + int r = UPP::GlInit(hInstance); \ + if(r > 0) { \ + GuiMainFn_(); \ + UPP::Ctrl::CloseTopCtrls(); \ + UPP::UsrLog("---------- About to delete this log of WinGL..."); \ + UPP::DeleteUsrLog(); \ + return UPP::GetExitCode(); \ + } else { \ + Exclamation(Format("OpenGL window could not be initialized: %d", r)); \ + return r; \ + }\ } \ \ void GuiMainFn_() diff --git a/rainbow/WinGl/ChSysInit.cpp b/rainbow/WinGl/ChSysInit.cpp new file mode 100644 index 000000000..dcd99f475 --- /dev/null +++ b/rainbow/WinGl/ChSysInit.cpp @@ -0,0 +1,16 @@ +#include + +#ifdef GUI_WINGL + +NAMESPACE_UPP + +void ChSysInit() +{ + CtrlImg::Reset(); + CtrlsImg::Reset(); + ChReset(); +} + +END_UPP_NAMESPACE + +#endif diff --git a/rainbow/WinGl/Clip.cpp b/rainbow/WinGl/Clip.cpp new file mode 100644 index 000000000..5cdb0e235 --- /dev/null +++ b/rainbow/WinGl/Clip.cpp @@ -0,0 +1,241 @@ +#include +#include + +#ifdef GUI_WINGL + +NAMESPACE_UPP + +#define LLOG(x) // LOG(x) + +void ClearClipboard() +{ + GuiLock __; +} + +void AppendClipboard(int format, const byte *data, int length) +{ + GuiLock __; +} + +void AppendClipboard(const char *format, const byte *data, int length) +{ + GuiLock __; +} + +void AppendClipboard(const char *format, const String& data) +{ + GuiLock __; + AppendClipboard(format, data, data.GetLength()); +} + +void AppendClipboard(const char *format, const Value& data, String (*render)(const Value&)) +{ + GuiLock __; +} + +String ReadClipboard(const char *format) +{ + GuiLock __; + return Null; +} + +void AppendClipboardText(const String& s) +{ + AppendClipboard("text", ToSystemCharset(s)); +} + +void AppendClipboardUnicodeText(const WString& s) +{ + AppendClipboard("wtext", (byte *)~s, 2 * s.GetLength()); +} + +const char *ClipFmtsText() +{ + return "wtext;text"; +} + +String GetString(PasteClip& clip) +{ + GuiLock __; + if(clip.Accept("wtext")) { + String s = ~clip; + return WString((const wchar *)~s, wstrlen((const wchar *)~s)).ToString(); + } + if(clip.IsAvailable("text")) + return ~clip; + return Null; +} + +WString GetWString(PasteClip& clip) +{ + GuiLock __; + if(clip.Accept("wtext")) { + String s = ~clip; + return WString((const wchar *)~s, wstrlen((const wchar *)~s)); + } + if(clip.IsAvailable("text")) + return (~clip).ToWString(); + return Null; +} + + +bool AcceptText(PasteClip& clip) +{ + return clip.Accept(ClipFmtsText()); +} + +static String sText(const Value& data) +{ + return data; +} + +static String sWText(const Value& data) +{ + return Unicode__(WString(data)); +} + +void Append(VectorMap& data, const String& text) +{ + data.GetAdd("text", ClipData(text, sText)); + data.GetAdd("wtext", ClipData(text, sWText)); +} + +void Append(VectorMap& data, const WString& text) +{ + data.GetAdd("text", ClipData(text, sText)); + data.GetAdd("wtext", ClipData(text, sWText)); +} + +String GetTextClip(const WString& text, const String& fmt) +{ + if(fmt == "text") + return text.ToString(); + if(fmt == "wtext") + return Unicode__(text); + return Null; +} + +String GetTextClip(const String& text, const String& fmt) +{ + if(fmt == "text") + return text; + if(fmt == "wtext") + return Unicode__(text.ToWString()); + return Null; +} + +String ReadClipboardText() +{ + return ReadClipboardUnicodeText().ToString(); +} + +WString ReadClipboardUnicodeText() +{ + return Null; +} + +bool IsClipboardAvailable(const char *id) +{ + return false; +} + +bool IsClipboardAvailableText() +{ + return false; +} + +const char *ClipFmtsImage() +{ + static const char *q; + ONCELOCK { + static String s = "dib;" + ClipFmt(); + q = s; + } + return q; +} + +bool AcceptImage(PasteClip& clip) +{ + GuiLock __; + return clip.Accept(ClipFmtsImage()); +} + +Image GetImage(PasteClip& clip) +{ + GuiLock __; + Image m; + if(Accept(clip)) { + LoadFromString(m, ~clip); + if(!m.IsEmpty()) + return m; + } + return Null; +} + +Image ReadClipboardImage() +{ + GuiLock __; + PasteClip d = Ctrl::Clipboard(); + return GetImage(d); +} + +String sImage(const Value& image) +{ + Image img = image; + return StoreAsString(const_cast(img)); +} + +String GetImageClip(const Image& img, const String& fmt) +{ + GuiLock __; + if(img.IsEmpty()) return Null; + if(fmt == ClipFmt()) + return sImage(img); + return Null; +} + +void AppendClipboardImage(const Image& img) +{ + GuiLock __; + if(img.IsEmpty()) return; + AppendClipboard(ClipFmt(), img, sImage); +} + +bool AcceptFiles(PasteClip& clip) +{ + if(clip.Accept("files")) { + clip.SetAction(DND_COPY); + return true; + } + return false; +} + +bool IsAvailableFiles(PasteClip& clip) +{ + return clip.IsAvailable("files"); +} + +Vector GetFiles(PasteClip& clip) +{ + GuiLock __; + Vector f; + return f; +} + +bool PasteClip::IsAvailable(const char *fmt) const +{ + return false; +} + +String PasteClip::Get(const char *fmt) const +{ + return Null; +} + +void PasteClip::GuiPlatformConstruct() +{ +} + +END_UPP_NAMESPACE + +#endif diff --git a/rainbow/WinGl/Ctrl.h b/rainbow/WinGl/Ctrl.h index 6ca03df35..45b3335dc 100644 --- a/rainbow/WinGl/Ctrl.h +++ b/rainbow/WinGl/Ctrl.h @@ -1,5 +1,20 @@ //$ class Ctrl { + static Ptr desktop; + static Vector topctrl; + + static Point fbCursorPos; + static Image fbCursorImage; + + static Point fbCursorBakPos; + static Image fbCursorBak; + + static Rect fbCaretRect; + static Image fbCaretBak; + static int fbCaretTm; + + int FindTopCtrl() const; public: + static void InitGl(); static void DoMouseGl(int event, Point p, int zdelta = 0); static bool DoKeyGl(dword key, int cnt); @@ -7,7 +22,10 @@ public: static void RemoveCaret(); static void CursorSync(); - static Image GetBak(Rect& tr); void SetOpen(bool b) { isopen = b; } void SetTop() { top = new Top; } + + static void SetDesktop(Ctrl& q); + static Ctrl *GetDesktop() { return desktop; } + //$ }; diff --git a/rainbow/WinGl/Dnd.cpp b/rainbow/WinGl/Dnd.cpp new file mode 100644 index 000000000..79efd9ff0 --- /dev/null +++ b/rainbow/WinGl/Dnd.cpp @@ -0,0 +1,40 @@ +#include + +#ifdef GUI_WINGL + +NAMESPACE_UPP + +#define LLOG(x) // LOG(x) + +// -------------------------------------------------------------------------------------------- + +Ptr sDnDSource; + +Ctrl * Ctrl::GetDragAndDropSource() +{ + return sDnDSource; +} + +Image MakeDragImage(const Image& arrow, Image sample); + +Image MakeDragImage(const Image& arrow, const Image& arrow98, Image sample) +{ +#if PLATFORM_WIN32 + if(IsWin2K()) + return MakeDragImage(arrow, sample); + else +#endif + return arrow98; +} + +int Ctrl::DoDragAndDrop(const char *fmts, const Image& sample, dword actions, + const VectorMap& data) +{ + return DND_NONE; +} + +void Ctrl::SetSelectionSource(const char *fmts) {} + +END_UPP_NAMESPACE + +#endif diff --git a/rainbow/WinGl/Draw.cpp b/rainbow/WinGl/Draw.cpp index 1693337eb..d3bf45390 100644 --- a/rainbow/WinGl/Draw.cpp +++ b/rainbow/WinGl/Draw.cpp @@ -7,6 +7,7 @@ NAMESPACE_UPP #define LLOG(x) // LOG(x) #define LTIMING(x) // RTIMING(x) +int64 Resources::currentSerialId = -1; ArrayMap Resources::textures; VectorMap Resources::fonts; @@ -99,9 +100,7 @@ OpenGLFont& Resources::GetFont(const char* fontName) OpenGLFont& Resources::StdFont(bool bold) { -// return GetFont(bold ? "tahoma14b.fnt" : "tahoma14.fnt"); -// return GetFont(bold ? "tahoma.fnt" : "tahoma.fnt"); - return GetFont(bold ? "arial.fnt" : "arial.fnt"); + return GetFont(bold ? "tahoma14b.fnt" : "tahoma14.fnt"); } dword SystemDraw::GetInfo() const @@ -208,8 +207,6 @@ void SystemDraw::FlatView() glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, drawing_size.cx, drawing_size.cy, 0, -100, 100); - //glFrustum(0, drawing_size.cx, drawing_size.cy, 0, -100, 100); - //gluPerspective(45, 1, -100, 100); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); float dx = (float) drawing_size.cx / 2; @@ -228,7 +225,6 @@ void SystemDraw::PopContext() FlatView(); } - SystemDraw::~SystemDraw() { } diff --git a/rainbow/WinGl/DrawOp.cpp b/rainbow/WinGl/DrawOp.cpp new file mode 100644 index 000000000..b856e517b --- /dev/null +++ b/rainbow/WinGl/DrawOp.cpp @@ -0,0 +1,412 @@ +#include + +#ifdef GUI_WINGL + +NAMESPACE_UPP + +#pragma comment( lib, "opengl32.lib" ) // Search For OpenGL32.lib While Linking +#pragma comment( lib, "glu32.lib" ) // Search For GLu32.lib While Linking + +#define LLOG(x) // LOG(x) +#define LTIMING(x) // RTIMING(x) + +void SystemDraw::PlaneEquation(double eq[4], float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3) +{ + eq[0] = y1 * (z2 - z3) + + y2 * (z3 - z1) + + y3 * (z1 - z2); + + eq[1] = z1 * (x2 - x3) + + z2 * (x3 - x1) + + z3 * (x1 - x2); + + eq[2] = x1 * (y2 - y3) + + x2 * (y3 - y1) + + x3 * (y1 - y2); + + eq[3] = -(x1 * (y2 * z3 - y3 * z2) + + x2 * (y3 * z1 - y1 * z3) + + x3 * (y1 * z2 - y2 * z1)); +} + +void SystemDraw::SetClipRect(const Rect& r) +{ + clip = r; +#if CLIP_MODE != 2 + for(int i = 0; i < ci; i++) + clip &= cloff[i].drawing_clip; +#endif +} + +void SystemDraw::ScissorClip(const Rect& r) +{ + glScissor(r.left, drawing_size.cy - r.top - r.Height(), r.Width(), r.Height()); +} + +void SystemDraw::PlaneClip(const Rect& r) +{ + float cl = (float) r.left; + float ct = (float) r.top; + float cr = (float) r.right; + float cb = (float) r.bottom; + + double eq[4]; + + PlaneEquation(eq, cl, ct, 0, cl, cb, 0, cl, cb, +1.0f); + glClipPlane(GL_CLIP_PLANE0, eq); + + PlaneEquation(eq, cr, ct, 0, cr, cb, 0, cr, cb, -1.0f); + glClipPlane(GL_CLIP_PLANE1, eq); + + PlaneEquation(eq, cl, ct, 0, cr, ct, 0, cr, ct, -1.0f); + glClipPlane(GL_CLIP_PLANE2, eq); + + PlaneEquation(eq, cl, cb, 0, cr, cb, 0, cr, cb, +1.0f); + glClipPlane(GL_CLIP_PLANE3, eq); +} + +void SystemDraw::SetVec(float* v, float sx, float sy, float dx, float dy) +{ + v[0] = sx; v[1] = dy; + v[2] = sx; v[3] = sy; + v[4] = dx; v[5] = dy; + v[6] = dx; v[7] = sy; +} + +void SystemDraw::SetVec(float* v, int sx, int sy, int dx, int dy) +{ + v[0] = (float) sx; v[1] = (float) dy; + v[2] = (float) sx; v[3] = (float) sy; + v[4] = (float) dx; v[5] = (float) dy; + v[6] = (float) dx; v[7] = (float) sy; +} + +void SystemDraw::StencilClip(const Rect& r, int mode) +{ + float vtx[] = { + (float) r.left, (float) r.bottom, + (float) r.left, (float) r.top, + (float) r.right, (float) r.bottom, + (float) r.right, (float) r.top + }; + + //SetVec(vtx, r.left, r.top, r.right, r.bottom); + glVertexPointer(2, GL_FLOAT, 0, vtx); + + glColorMask(0, 0, 0, 0); + if(mode == 0) + { + ++cn; + glStencilOp(GL_KEEP, GL_INCR, GL_INCR); + glStencilFunc(GL_GEQUAL, cn, ~0); + } + else + { + --cn; + glStencilOp(GL_KEEP, GL_DECR, GL_DECR); + glStencilFunc(GL_ALWAYS, cn, ~0); + } + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glStencilFunc(GL_LEQUAL, cn, ~0); + glColorMask(1, 1, 1, 1); + + /* + if(mode == 0) + { + glColorMask(0, 0, 0, 0); + glStencilOp(GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP); + glStencilFunc(GL_EQUAL, cn, ~0); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glStencilFunc(GL_LEQUAL, ++cn, ~0); + glColorMask(1, 1, 1, 1); + //cn = cd; + } + else + { + glStencilFunc(GL_LEQUAL, --cn, ~0); + } + */ + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); +} + +void SystemDraw::SetClip(const Rect& r, int mode) +{ + //glColor4ub(255, 0, 0, 10); + //glRecti(r.left, r.top, r.right, r.bottom); + SetClipRect(r); + +#if CLIP_MODE == 0 + ScissorClip(clip); +#elif CLIP_MODE == 1 + PlaneClip(clip); +#elif CLIP_MODE == 2 + StencilClip(clip, mode); +#endif +} + +void SystemDraw::BeginOp() +{ + Cloff& w = cloff[ci++]; + w.clipping = true; + w.org = drawing_offset; + w.drawing_clip = drawing_clip; +} + +void SystemDraw::EndOp() +{ + ASSERT(ci); +#if CLIP_MODE == 2 + if(cloff[ci - 1].clipping) + SetClip(drawing_clip, 1); +#endif + Cloff& w = cloff[--ci]; + drawing_offset = w.org; + drawing_clip = w.drawing_clip; +#if CLIP_MODE != 2 + if(cloff[ci].clipping) + SetClip(drawing_clip, 1); +#endif +} + +void SystemDraw::OffsetOp(Point p) +{ + BeginOp(); + cloff[ci - 1].clipping = false; + drawing_offset += p; +} + +bool SystemDraw::ClipOp(const Rect& r) +{ + BeginOp(); + drawing_clip = r + drawing_offset; + SetClip(drawing_clip); + return true; +} + +bool SystemDraw::ClipoffOp(const Rect& r) +{ + BeginOp(); + drawing_clip = r + drawing_offset; + drawing_offset += r.TopLeft(); + SetClip(drawing_clip); + return true; +} + +bool SystemDraw::ExcludeClipOp(const Rect& r) +{ + return true; +} + +bool SystemDraw::IntersectClipOp(const Rect& r) +{ + Cloff& w = cloff[ci]; + drawing_clip = r + drawing_offset; + SetClip(drawing_clip); + return true; +} + +bool SystemDraw::IsPaintingOp(const Rect& r) const +{ + return true; +} + +Rect SystemDraw::GetPaintRect() const +{ + return drawing_clip; +} + +void SystemDraw::DrawRectOp(int x, int y, int cx, int cy, Color color) +{ + if(IsNull(color)) + return; + + if(cx <= 0 || cy <= 0) return; + + float sx = (float) x + drawing_offset.x; + float sy = (float) y + drawing_offset.y; + float dx = sx + cx; + float dy = sy + cy; + +#if CLIP_MODE == 3 + float cl = (float) clip.left; + float ct = (float) clip.top; + float cr = (float) clip.right; + float cb = (float) clip.bottom; + + if(sx > cr || sy > cb) + return; + + if(dx < cl || dy < ct) + return; + + if(sx < cl) + sx = cl; + if(sy < ct) + sy = ct; + if(dx > cr) + dx = cr; + if(dy > cb) + dy = cb; +#endif + + glColor4ub(color.GetR(), color.GetG(), color.GetB(), (int) alpha); + + float vtx[] = { + sx, dy, + sx, sy, + dx, dy, + dx, sy + }; + + //SetVec(vtx, sx, sy, dx, dy); + + + glVertexPointer(2, GL_FLOAT, 0, vtx); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glColor4ub(255, 255, 255, (int) alpha); +} + +void SystemDraw::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color) +{ + if(cx <= 0 || cy <= 0) return; + + float sx = (float) x + drawing_offset.x; + float sy = (float) y + drawing_offset.y; + float dx = sx + cx; + float dy = sy + cy; + +#if CLIP_MODE == 3 + if(sx > clip.right || sy > clip.bottom) + return; + + if(dx < clip.left || dy < clip.top) + return; +#endif + + float tl = (float) src.left; + float tr = (float) src.right; + float tt = (float) src.top; + float tb = (float) src.bottom; + + float sw = (float) src.GetWidth(); + float sh = (float) src.GetHeight(); + +#if CLIP_MODE == 3 + float cl = (float) clip.left; + float ct = (float) clip.top; + float cr = (float) clip.right; + float cb = (float) clip.bottom; + + if(sx < cl) + { + float dl = cl - sx; + tl += dl * sw / (float) cx; + sx = cl; + } + + if(sy < ct) + { + float dt = ct - sy; + tt += dt * sh / (float) cy; + sy = ct; + } + + if(dx > cr) + { + float dr = dx - cr; + tr -= dr * sw / (float) cx; + dx = cr; + } + + if(dy > cb) + { + float db = dy - cb; + tb -= db * sh / (float) cy; + dy = cb; + } +#endif + + Resources::Bind(img); + + float tw = 1.f / (float) img.GetWidth(); + float th = 1.f / (float) img.GetHeight(); + + tl *= tw; + tr *= tw; + tt *= th; + tb *= th; + + if(IsNull(color)) + glColor4ub(255, 255, 255, (int) alpha); + else + glColor4ub(color.GetR(), color.GetG(), color.GetB(), (int) alpha); + //if(!IsNull(color)) + // glColor4ub(color.GetR(), color.GetG(), color.GetB(), (int) alpha); + + glEnable(GL_TEXTURE_2D); + + float vtx[] = { + sx, dy, + sx, sy, + dx, dy, + dx, sy + }; + + float crd[] = { + tl, tb, + tl, tt, + tr, tb, + tr, tt + }; + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, crd); + glVertexPointer(2, GL_FLOAT, 0, vtx); + //SetVec(vtx, sx, sy, dx, dy); + //SetVec(crd, tl, tt, tr, tb); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glDisable(GL_TEXTURE_2D); +} + +void SystemDraw::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color) +{ + glColor4ub(color.GetR(), color.GetG(), color.GetB(), (int) alpha); + glLineWidth((GLfloat) width); + glBegin(GL_LINES); + glVertex2i(x1 + drawing_offset.x, y1 + drawing_offset.y); + glVertex2i(x2 + drawing_offset.x, y2 + drawing_offset.y); + glEnd(); +} + +void SystemDraw::DrawPolyPolylineOp(const Point *vertices, int vertex_count, const int *counts, int count_count, int width, Color color, Color doxor) +{ +} + +void SystemDraw::DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, const int *subpolygon_counts, int scc, const int *disjunct_polygon_counts, int dpcc, Color color, int width, Color outline, uint64 pattern, Color doxor) +{ +} + +void SystemDraw::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color) +{ +} + +void SystemDraw::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor) +{ +} + +void SystemDraw::SaveCurrentColor() +{ + glGetFloatv(GL_CURRENT_COLOR, current_color); +} + +void SystemDraw::RestoreLastColor() +{ + glColor4f(current_color[0], current_color[1], current_color[2], current_color[3]); +} + +END_UPP_NAMESPACE + +#endif \ No newline at end of file diff --git a/rainbow/WinGl/DrawText.cpp b/rainbow/WinGl/DrawText.cpp new file mode 100644 index 000000000..a15060695 --- /dev/null +++ b/rainbow/WinGl/DrawText.cpp @@ -0,0 +1,273 @@ +#include + +#ifdef GUI_WINGL + +NAMESPACE_UPP + +void OpenGLFont::Load(const String& fileName) +{ + String filePath = GetDataFile(fileName); + String xml = LoadFile(filePath); + XmlParser p(xml); + float scale = 1.0f / 1.f; + + while(!p.IsTag()) + p.Skip(); + + p.PassTag("font"); + + while(!p.End()) + { + if(p.TagE("common")) + { + scaleW = (float) p.Double("scaleW"); + scaleH = (float) p.Double("scaleH"); + lineHeight = (float) p.Double("lineHeight"); + base = (float) p.Double("base"); + } + else if(p.Tag("pages")) + { + while(!p.End()) + { + if(p.TagE("page")) + { + String fileName = p["file"]; + files.Add(fileName); + //Image img = StreamRaster::LoadFileAny(GetDataFile(fileName)); + //int serialId = Resources::Bind(img); + pages.Add(-1); + } + else + p.Skip(); + } + + } + else if(p.Tag("chars")) + { + while(!p.End()) + { + if(p.TagE("char")) + { + CharInfo& ci = chars.Add(); + + int page = p.Int("page"); + + ci.id = p.Int("id"); + ci.x = (float) p.Double("x"); + ci.y = (float) p.Double("y"); + ci.width = (float) p.Double("width"); + ci.height = (float) p.Double("height"); + ci.xoffset = (float) p.Double("xoffset"); + ci.yoffset = (float) p.Double("yoffset"); + ci.xadvance = (float) p.Double("xadvance"); + ci.page = page; + + ci.x *= scale; + ci.y *= scale; + ci.width *= scale; + ci.height *= scale; + ci.xoffset *= scale; + ci.yoffset *= scale; + ci.xadvance *= scale; + } + else + p.Skip(); + } + } + else if(p.Tag("kernings")) + { + while(!p.End()) + { + if(p.TagE("kerning")) + { + int first = p.Int("first"); + int second = p.Int("second"); + float amount = (float) p.Double("amount"); + + VectorMap& vm = kerns.GetAdd(first); + vm.Add(second, amount * scale); + } + else + p.Skip(); + } + } + else + p.Skip(); + } +} + +void OpenGLFont::UpdateTextures() +{ + if(texturesUpdated) + return; + + for(int i = 0; i < files.GetCount(); i++) + { + Image img = StreamRaster::LoadFileAny(GetDataFile(files[i])); + int64 serialId = Resources::Bind(img, true); + pages[i] = serialId; + } + + texturesUpdated = true; +} + +//extern int gpuProgram; + +void SystemDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx) +{ + if(!text) + return; + + const wchar* s = text; + OpenGLFont& fi = Resources::StdFont(font.IsBold()); + + glColor4ub(ink.GetR(), ink.GetG(), ink.GetB(), (int) alpha); + glEnable(GL_TEXTURE_2D); + + #if CLIP_MODE == 3 + float cl = (float) clip.left; + float ct = (float) clip.top; + float cr = (float) clip.right; + float cb = (float) clip.bottom; + #endif + fi.UpdateTextures(); + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); +// glUseProgram(gpuProgram); + + float xp = (float) x; + float yp = (float) y; + + while(*s && n > 0) + { + int ch = *s; + int cn = ch - 32; + + if(cn >= 0 && cn < fi.chars.GetCount()) + { + const OpenGLFont::CharInfo& ci = fi.chars[cn]; + + cn <<= 3; + + Resources::Bind(fi.pages[ci.page], true); + //int my_sampler_uniform_location = glGetUniformLocation(gpuProgram, "textMap"); + //glActiveTexture(GL_TEXTURE0); + //glUniform1i(my_sampler_uniform_location, 0); + + float sx = (float) ci.xoffset + xp + drawing_offset.x; + float sy = (float) ci.yoffset + yp + drawing_offset.y; + float dx = sx + ci.width; + float dy = sy + ci.height; + + #if CLIP_MODE == 3 + if(sx <= clip.right && sy <= clip.bottom && dx >= clip.left && dy >= clip.top) + #endif + { + float tl = (float) ci.x; + float tt = (float) ci.y; + float tr = (float) ci.x + ci.width; + float tb = (float) ci.y + ci.height; + + float sw = (float) fi.scaleW; + float sh = (float) fi.scaleH; + + #if CLIP_MODE == 3 + if(sx < cl) + { + tl += (cl - sx); + sx = cl; + } + + if(sy < ct) + { + tt += (ct - sy); + sy = ct; + } + + if(dx > cr) + { + tr -= dx - cr; + dx = cr; + } + + if(dy > cb) + { + tb -= dy - cb; + dy = cb; + } + #endif + + float tw = 1.f / sw; + float th = 1.f / sh; + + tl *= tw; + tt *= th; + tr *= tw; + tb *= th; + + float vtx[] = { + sx, dy, + sx, sy, + dx, dy, + dx, sy + }; + + float crd[] = { + tl, tb, + tl, tt, + tr, tb, + tr, tt + }; + //SetVec(vtx, sx, sy, dx, dy); + //SetVec(crd, tl, tt, tr, tb); + + glTexCoordPointer(2, GL_FLOAT, 0, crd); + glVertexPointer(2, GL_FLOAT, 0, vtx); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + + xp += ci.xadvance; + + int k = fi.kerns.Find(*s); + if(k >= 0) + xp += fi.kerns[k].Get(*(s + 1), 0); + } + + ++s; + --n; + } + + glUseProgram(0); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisable(GL_TEXTURE_2D); + glColor4ub(255, 255, 255, (int) alpha); +} + +Size GetTextSize(const wchar *text, const OpenGLFont& fi, int n) +{ + if(n < 0) + n = wstrlen(text); + Sizef sz; + sz.cx = 0; + const wchar *wtext = (const wchar *)text; + while(n > 0) { + int ch = *wtext++; + int cn = ch - 32; + + if(cn >= 0 && cn < fi.chars.GetCount()) + { + const OpenGLFont::CharInfo& ci = fi.chars[cn]; + sz.cx += ci.xadvance; + int k = fi.kerns.Find(ch); + if(k >= 0) + sz.cx += fi.kerns[k].Get(*wtext, 0); + } + n--; + } + sz.cy = fi.lineHeight; + return sz; +} + +END_UPP_NAMESPACE + +#endif \ No newline at end of file diff --git a/rainbow/WinGl/Event.cpp b/rainbow/WinGl/Event.cpp index af6488608..5e9dde98a 100644 --- a/rainbow/WinGl/Event.cpp +++ b/rainbow/WinGl/Event.cpp @@ -6,15 +6,15 @@ NAMESPACE_UPP #define LLOG(x) LOG(x) -static Point fbmousepos; +static Point glmousepos; Point GetMousePos() { - return fbmousepos; + return glmousepos; } void Ctrl::DoMouseGl(int event, Point p, int zdelta) { - fbmousepos = p; + glmousepos = p; int a = event & Ctrl::ACTION; if(a == Ctrl::UP && Ctrl::ignoreclick) { EndIgnore(); @@ -51,19 +51,6 @@ Rect fbCaretRect; Image fbCaretBak; int fbCaretTm; -Image Ctrl::GetBak(Rect& tr) -{ - Image bak; - tr.Intersect(framebuffer.GetSize()); - if(!tr.IsEmpty()) { - Image h = framebuffer; - bak = CreateImage(tr.GetSize(), Black); - Copy(bak, Point(0, 0), h, tr); - framebuffer = h; - } - return bak; -} - void Ctrl::RemoveCursor() { } diff --git a/rainbow/WinGl/Image.cpp b/rainbow/WinGl/Image.cpp new file mode 100644 index 000000000..176cfa38b --- /dev/null +++ b/rainbow/WinGl/Image.cpp @@ -0,0 +1,125 @@ +#include + +#ifdef GUI_WINGL + +//#include + +NAMESPACE_UPP + +#define LTIMING(x) // RTIMING(x) + +void SetSurface(SystemDraw& w, int x, int y, int cx, int cy, const RGBA *pixels) +{ + GuiLock __; +} + +void SetSurface(SystemDraw& w, const Rect& dest, const RGBA *pixels, Size psz, Point poff) +{ + GuiLock __; +} + +struct Image::Data::SystemData { +}; + +void Image::Data::SysInitImp() +{ + SystemData& sd = Sys(); +} + +void Image::Data::SysReleaseImp() +{ + SystemData& sd = Sys(); +} + +Image::Data::SystemData& Image::Data::Sys() const +{ + ASSERT(sizeof(system_buffer) >= sizeof(SystemData)); + return *(SystemData *)system_buffer; +} + +int Image::Data::GetResCountImp() const +{ + SystemData& sd = Sys(); + return 0; +} + +void Image::Data::PaintImp(SystemDraw& w, int x, int y, const Rect& src, Color c) +{ + GuiLock __; + SystemData& sd = Sys(); +} + +Image ImageDraw::Get(bool pm) const +{ + ImageBuffer result(image.GetSize()); + const RGBA *e = image.End(); + const RGBA *p = ~image; + RGBA *t = ~result; + if(has_alpha) { + const RGBA *a = ~alpha; + while(p < e) { + *t = *p++; + (t++)->a = (a++)->r; + } + if(pm) + Premultiply(result); + result.SetKind(IMAGE_ALPHA); + } + else { + while(p < e) { + *t = *p++; + (t++)->a = 255; + } + } + return result; +} + +Draw& ImageDraw::Alpha() +{ + has_alpha = true; + return alpha_painter; +} + + +ImageDraw::ImageDraw(Size sz) +: ImageDraw__(sz.cx, sz.cy), + BufferPainter(image), + alpha_painter(alpha) +{ + has_alpha = false; +} + +ImageDraw::ImageDraw(int cx, int cy) +: ImageDraw__(cx, cy), + BufferPainter(image), + alpha_painter(alpha) +{ + has_alpha = false; +} + +#define IMAGECLASS FBImg +#define IMAGEFILE +#include +#define IMAGECLASS FBImg +#define IMAGEFILE +#include + +Image Image::Arrow() { return FBImg::arrow(); } +Image Image::Wait() { return FBImg::wait(); } +Image Image::IBeam() { return FBImg::ibeam(); } +Image Image::No() { return FBImg::no(); } +Image Image::SizeAll() { return FBImg::sizeall(); } +Image Image::SizeHorz() { return FBImg::sizehorz(); } +Image Image::SizeVert() { return FBImg::sizevert(); } +Image Image::SizeTopLeft() { return FBImg::sizetopleft(); } +Image Image::SizeTop() { return FBImg::sizetop(); } +Image Image::SizeTopRight() { return FBImg::sizetopright(); } +Image Image::SizeLeft() { return FBImg::sizeleft(); } +Image Image::SizeRight() { return FBImg::sizeright(); } +Image Image::SizeBottomLeft() { return FBImg::sizebottomleft(); } +Image Image::SizeBottom() { return FBImg::sizebottom(); } +Image Image::SizeBottomRight() { return FBImg::sizebottomright(); } + +END_UPP_NAMESPACE + +#endif diff --git a/rainbow/WinGl/Proc.cpp b/rainbow/WinGl/Proc.cpp index 9e41e652a..d438b3893 100644 --- a/rainbow/WinGl/Proc.cpp +++ b/rainbow/WinGl/Proc.cpp @@ -63,40 +63,40 @@ LRESULT CALLBACK glWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa } return 0L; case WM_LBUTTONDOWN: - Ctrl::DoMouseFB(Ctrl::LEFTDOWN, Point((dword)lParam)); + Ctrl::DoMouseGl(Ctrl::LEFTDOWN, Point((dword)lParam)); return 0L; case WM_LBUTTONUP: - Ctrl::DoMouseFB(Ctrl::LEFTUP, Point((dword)lParam)); + Ctrl::DoMouseGl(Ctrl::LEFTUP, Point((dword)lParam)); return 0L; case WM_LBUTTONDBLCLK: - Ctrl::DoMouseFB(Ctrl::LEFTDOUBLE, Point((dword)lParam)); + Ctrl::DoMouseGl(Ctrl::LEFTDOUBLE, Point((dword)lParam)); return 0L; case WM_RBUTTONDOWN: - Ctrl::DoMouseFB(Ctrl::RIGHTDOWN, Point((dword)lParam)); + Ctrl::DoMouseGl(Ctrl::RIGHTDOWN, Point((dword)lParam)); return 0L; case WM_RBUTTONUP: - Ctrl::DoMouseFB(Ctrl::RIGHTUP, Point((dword)lParam)); + Ctrl::DoMouseGl(Ctrl::RIGHTUP, Point((dword)lParam)); return 0L; case WM_RBUTTONDBLCLK: - Ctrl::DoMouseFB(Ctrl::RIGHTDOUBLE, Point((dword)lParam)); + Ctrl::DoMouseGl(Ctrl::RIGHTDOUBLE, Point((dword)lParam)); return 0L; case WM_MBUTTONDOWN: - Ctrl::DoMouseFB(Ctrl::MIDDLEDOWN, Point((dword)lParam)); + Ctrl::DoMouseGl(Ctrl::MIDDLEDOWN, Point((dword)lParam)); return 0L; case WM_MBUTTONUP: - Ctrl::DoMouseFB(Ctrl::MIDDLEUP, Point((dword)lParam)); + Ctrl::DoMouseGl(Ctrl::MIDDLEUP, Point((dword)lParam)); return 0L; case WM_MBUTTONDBLCLK: - Ctrl::DoMouseFB(Ctrl::MIDDLEDOUBLE, Point((dword)lParam)); + Ctrl::DoMouseGl(Ctrl::MIDDLEDOUBLE, Point((dword)lParam)); return 0L; case WM_MOUSEMOVE: - Ctrl::DoMouseFB(Ctrl::MOUSEMOVE, Point((dword)lParam)); + Ctrl::DoMouseGl(Ctrl::MOUSEMOVE, Point((dword)lParam)); return 0L; case 0x20a: // WM_MOUSEWHEEL: { Point p(0, 0); ::ClientToScreen(hwnd, p); - Ctrl::DoMouseFB(Ctrl::MOUSEWHEEL, Point((dword)lParam) - p, (short)HIWORD(wParam)); + Ctrl::DoMouseGl(Ctrl::MOUSEWHEEL, Point((dword)lParam) - p, (short)HIWORD(wParam)); } return 0L; case WM_SETCURSOR: @@ -146,7 +146,7 @@ LRESULT CALLBACK glWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa keycode = (dword)wParam; bool b = false; if(keycode) - b = Ctrl::DoKeyFB(keycode, LOWORD(lParam)); + b = Ctrl::DoKeyGl(keycode, LOWORD(lParam)); // LOG("key processed = " << b); // if(b || (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP) // && wParam != VK_F4 && !PassWindowsKey((dword)wParam)) // 17.11.2003 Mirek -> invoke system menu @@ -164,7 +164,7 @@ LRESULT CALLBACK glWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa case WM_HELP: return TRUE; case WM_CLOSE: - fbEndSession = true; + glEndSession = true; } return DefWindowProc(hwnd, message, wParam, lParam); } diff --git a/rainbow/WinGl/Top.cpp b/rainbow/WinGl/Top.cpp new file mode 100644 index 000000000..33d38f265 --- /dev/null +++ b/rainbow/WinGl/Top.cpp @@ -0,0 +1,82 @@ +#include + +#ifdef GUI_WINGL + +NAMESPACE_UPP + +#define LLOG(x) // LOG(x) + +void TopWindow::SyncSizeHints() {} + +void TopWindow::SyncTitle0() +{ + GuiLock __; +} + +void TopWindow::SyncCaption0() +{ + GuiLock __; +} + +void TopWindow::Open(Ctrl *owner) +{ + GuiLock __; +} + +void TopWindow::Open() +{ + painting = false; +} + +void TopWindow::OpenMain() +{ +} + +void TopWindow::Minimize(bool effect) +{ + state = MINIMIZED; +} + +TopWindow& TopWindow::FullScreen(bool b) +{ + return *this; +} + +void TopWindow::Maximize(bool effect) +{ + state = MAXIMIZED; +} + +void TopWindow::Overlap(bool effect) +{ + GuiLock __; + state = OVERLAPPED; +} + +TopWindow& TopWindow::TopMost(bool b, bool stay_top) +{ + GuiLock __; + return *this; +} + +bool TopWindow::IsTopMost() const +{ + return true; +} + +void TopWindow::GuiPlatformConstruct() +{ +} + +void TopWindow::GuiPlatformDestruct() +{ +} + +void TopWindow::SerializePlacement(Stream& s, bool reminimize) +{ + GuiLock __; +} + +END_UPP_NAMESPACE + +#endif diff --git a/rainbow/WinGl/Top.h b/rainbow/WinGl/Top.h index bdd5b8bab..64ae70937 100644 --- a/rainbow/WinGl/Top.h +++ b/rainbow/WinGl/Top.h @@ -1,3 +1,3 @@ //$ class TopWindow { - +bool painting; //$ }; \ No newline at end of file diff --git a/rainbow/WinGl/Util.cpp b/rainbow/WinGl/Util.cpp new file mode 100644 index 000000000..afd19a1c8 --- /dev/null +++ b/rainbow/WinGl/Util.cpp @@ -0,0 +1,20 @@ +#include + +#ifdef GUI_WINGL + +NAMESPACE_UPP + +void DrawDragRect(SystemDraw& w, const Rect& rect1, const Rect& rect2, const Rect& clip, int n, Color color, uint64 pattern) +{ +} + +/* +Size GetScreenSize() +{ + return ScreenInfo().GetPageSize(); +} +*/ + +END_UPP_NAMESPACE + +#endif diff --git a/rainbow/WinGl/Win.cpp b/rainbow/WinGl/Win.cpp index 871a17689..3a0959f7c 100644 --- a/rainbow/WinGl/Win.cpp +++ b/rainbow/WinGl/Win.cpp @@ -8,7 +8,7 @@ HWND glHWND; HDC hDC; HGLRC hRC; -bool glEndSession; +bool glEndSession = false; bool GlEndSession() { @@ -59,7 +59,7 @@ void DestroyGL() ReleaseDC(glHWND, hDC); } -void GlInit(HINSTANCE hInstance) +int GlInit(HINSTANCE hInstance) { GuiLock __; @@ -67,21 +67,25 @@ void GlInit(HINSTANCE hInstance) WNDCLASSW wc; Zero(wc); - wc.style = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW|CS_OWNDC; + wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = (WNDPROC)glWindowProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)NULL; wc.lpszClassName = L"UPP-FB-CLASS"; RegisterClassW(&wc); - glHWND = CreateWindowW(L"UPP-FB-CLASS", L"", WS_OVERLAPPED|WS_VISIBLE|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_SYSMENU, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - NULL, NULL, hInstance, NULL); + glHWND = CreateWindowW( + L"UPP-FB-CLASS", L"", + WS_OVERLAPPED | WS_VISIBLE | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, hInstance, NULL); + + if(!glHWND) + return -1; - - HDC hDC = ::GetDC(glHWND); + hDC = ::GetDC(glHWND); if(!hDC) - return; + return -2; PIXELFORMATDESCRIPTOR pfd; memset(&pfd, 0, sizeof(pfd)); pfd.nSize = sizeof(pfd); @@ -94,15 +98,14 @@ void GlInit(HINSTANCE hInstance) pfd.iLayerType = PFD_MAIN_PLANE; int pf = ChoosePixelFormat(hDC, &pfd); if(!pf) { - RLOG("OpenGL: ChoosePixelFormat error"); DestroyGL(); - return; + return -3; } if(!SetPixelFormat(hDC, pf, &pfd)) { RLOG("OpenGL: SetPixelFormat error"); DestroyGL(); - return; + return -4; } DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd); hRC = wglCreateContext(hDC); @@ -110,13 +113,13 @@ void GlInit(HINSTANCE hInstance) { RLOG("OpenGL: wglCreateContext error"); DestroyGL(); - return; + return -5; } if(!wglMakeCurrent(hDC, hRC)) { RLOG("OpenGL: wglMakeCurrent error"); DestroyGL(); - return; + return -6; } //ActivateGLContext(); GLenum err = glewInit(); @@ -124,15 +127,15 @@ void GlInit(HINSTANCE hInstance) { RLOG("OpenGL: Glew library initialization error: " + String((const char*) glewGetErrorString(err))); DestroyGL(); - return; + return -7; } //InitializeShaders(); //wglSwapIntervalEXT(0); //SetTimeCallback(-10, THISBACK(Repaint), 1); - //SetTimer(fbHWND, 1, 10, NULL); - + SetTimer(glHWND, 1, 10, NULL); + return 1; } END_UPP_NAMESPACE diff --git a/rainbow/WinGl/WinGl.h b/rainbow/WinGl/WinGl.h index ef34fdfee..5ec6a1075 100644 --- a/rainbow/WinGl/WinGl.h +++ b/rainbow/WinGl/WinGl.h @@ -8,12 +8,18 @@ #include #include +#include + #define GUI_WINGL NAMESPACE_UPP extern bool glEndSession; +extern HWND glHWND; +extern HDC hDC; +extern HGLRC hRC; +void ActivateGLContext(); LRESULT CALLBACK glWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #define GUI_FB @@ -93,6 +99,7 @@ class SystemDraw : public Draw { public: virtual dword GetInfo() const; virtual Size GetPageSize() const; + bool CanSetSurface() { return false; } void PlaneEquation(double eq[4], float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3); void SetClipRect(const Rect& r); @@ -225,7 +232,8 @@ struct ImageDraw__ { ImageDraw__(int cx, int cy) : image(cx, cy), alpha(cx, cy) {} }; -class ImageDraw : private ImageDraw__ { +class ImageDraw : private ImageDraw__, public BufferPainter { + BufferPainter alpha_painter; bool has_alpha; Image Get(bool pm) const; diff --git a/rainbow/WinGl/WinGl.upp b/rainbow/WinGl/WinGl.upp index 7dfb94c7f..a5ad81363 100644 --- a/rainbow/WinGl/WinGl.upp +++ b/rainbow/WinGl/WinGl.upp @@ -1,14 +1,26 @@ +options + "-D_WIN32 -DGLEW_STATIC"; + file WinGl.h, Keys.h, Draw.cpp, + DrawOp.cpp, + DrawText.cpp, Win.cpp, + Wnd.cpp, Proc.cpp, After.h, Event.cpp, Top.h, + Top.cpp, Ctrl.h, Ctrl.cpp, + Clip.cpp, + Dnd.cpp, + Image.cpp, + ChSysInit.cpp, + Util.cpp, Glew readonly separator, glew.h, glxew.h, diff --git a/rainbow/WinGl/Wnd.cpp b/rainbow/WinGl/Wnd.cpp new file mode 100644 index 000000000..432e1901c --- /dev/null +++ b/rainbow/WinGl/Wnd.cpp @@ -0,0 +1,418 @@ +#include + +#ifdef GUI_FB + +NAMESPACE_UPP + +#define LLOG(x) + +Ptr Ctrl::desktop; +Vector Ctrl::topctrl; + +Point Ctrl::fbCursorPos = Null; +Image Ctrl::fbCursorImage; +Point Ctrl::fbCursorBakPos = Null; +Image Ctrl::fbCursorBak; +Rect Ctrl::fbCaretRect; +Image Ctrl::fbCaretBak; +int Ctrl::fbCaretTm; + +void Ctrl::SetDesktop(Ctrl& q) +{ + desktop = &q; +// desktop->SetRect(framebuffer.GetSize()); + desktop->SetOpen(true); + desktop->SetTop(); +} + +void Ctrl::InitGl() +{ + Ctrl::InitTimer(); +} + +int Ctrl::FindTopCtrl() const +{ + for(int i = 0; i < topctrl.GetCount(); i++) + if(this == topctrl[i]) + return i; + return -1; +} + +bool Ctrl::IsAlphaSupported() +{ + return false; +} + +bool Ctrl::IsCompositedGui() +{ + return false; +} + +Vector Ctrl::GetTopCtrls() +{ + Vector ctrl; + if(desktop) + ctrl.Add(desktop); + for(int i = 0; i < topctrl.GetCount(); i++) + ctrl.Add(topctrl[i]); + return ctrl; +} + +Ctrl *Ctrl::GetOwner() +{ + GuiLock __; + return NULL; +} + +Ctrl *Ctrl::GetActiveCtrl() +{ + GuiLock __; + return desktop; +} + +// Vector Ctrl::hotkey; + +int Ctrl::RegisterSystemHotKey(dword key, Callback cb) +{ +/* ASSERT(key >= K_DELTA); + int q = hotkey.GetCount(); + for(int i = 0; i < hotkey.GetCount(); i++) + if(!hotkey[i]) { + q = i; + break; + } + hotkey.At(q) = cb; + dword mod = 0; + if(key & K_ALT) + mod |= MOD_ALT; + if(key & K_SHIFT) + mod |= MOD_SHIFT; + if(key & K_CTRL) + mod |= MOD_CONTROL; + + return RegisterHotKey(NULL, q, mod, key & 0xffff) ? q : -1;*/ + return -1; +} + +void Ctrl::UnregisterSystemHotKey(int id) +{ +/* if(id >= 0 && id < hotkey.GetCount()) { + UnregisterHotKey(NULL, id); + hotkey[id].Clear(); + }*/ +} + +bool Ctrl::IsWaitingEvent() +{ + return GlIsWaitingEvent(); +} + +bool Ctrl::ProcessEvent(bool *quit) +{ + ASSERT(IsMainThread()); + if(DoCall()) + return false; + if(GlEndSession()) { + if(quit) *quit = true; + return false; + } + if(!GetMouseLeft() && !GetMouseRight() && !GetMouseMiddle()) + ReleaseCtrlCapture(); + if(GlProcessEvent(quit)) { + DefferedFocusSync(); + SyncCaret(); + return true; + } + return false; +} + +bool Ctrl::ProcessEvents(bool *quit) +{ + if(!ProcessEvent(quit)) + return false; + while(ProcessEvent(quit) && (!LoopCtrl || LoopCtrl->InLoop()) && !GlEndSession()); // LoopCtrl-MF 071008 + TimerProc(GetTickCount()); + SweepMkImageCache(); + if(desktop && !painting) { + painting = true; + RemoveCursor(); + RemoveCaret(); + + ActivateGLContext(); + //SyncLayout(1); + //InitInfoPanel(); + Rect rect; + Size csz = rect.GetSize(); + Rect clip(csz); + SystemDraw draw(hDC, csz); + //draw.alpha = alpha; + //draw.angle = angle; + draw.FlatView(); + draw.Clear(); + //ApplyTransform(TS_BEFORE_PAINT); + desktop->CtrlPaint(draw, clip);//, &infoPanel); + //AnimateCaret(); + //ApplyTransform(TS_AFTER_PAINT); + SwapBuffers(hDC); + painting = false; + } + CursorSync(); + return false; +} + +void Ctrl::EventLoop0(Ctrl *ctrl) +{ + GuiLock __; + ASSERT(IsMainThread()); + ASSERT(LoopLevel == 0 || ctrl); + LoopLevel++; + LLOG("Entering event loop at level " << LoopLevel << BeginIndent); + Ptr ploop; + if(ctrl) { + ploop = LoopCtrl; + LoopCtrl = ctrl; + ctrl->inloop = true; + } + + bool quit = false; + ProcessEvents(&quit); + while(!GlEndSession() && !quit && ctrl ? ctrl->IsOpen() && ctrl->InLoop() : GetTopCtrls().GetCount()) + { +// LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": EventLoop / GuiSleep"); + SyncCaret(); + GuiSleep(20); + if(GlEndSession()) break; +// LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": EventLoop / ProcessEvents"); + ProcessEvents(&quit); +// LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": EventLoop / after ProcessEvents"); + } + + if(ctrl) + LoopCtrl = ploop; + LoopLevel--; + LLOG(EndIndent << "Leaving event loop "); +} + +void Ctrl::GuiSleep0(int ms) +{ + GuiLock __; + ASSERT(IsMainThread()); + LLOG("GuiSleep"); + if(GlEndSession()) + return; + LLOG("GuiSleep 2"); + int level = LeaveGMutexAll(); + GlSleep(ms); + EnterGMutex(level); +} + +Rect Ctrl::GetWndUpdateRect() const +{ + GuiLock __; + Rect r; + return Rect(0, 0, 1000, 600); +} + +Rect Ctrl::GetWndScreenRect() const +{ + GuiLock __; + return GetRect(); +} + +void Ctrl::WndShow0(bool b) +{ + GuiLock __; +} + +void Ctrl::WndUpdate0() +{ + GuiLock __; +} + +bool Ctrl::IsWndOpen() const { + GuiLock __; + return FindTopCtrl() >= 0 || this == desktop; +} + +void Ctrl::SetAlpha(byte alpha) +{ + GuiLock __; +} + +Rect Ctrl::GetWorkArea() const +{ + GuiLock __; + return Rect(); +} + +void Ctrl::GetWorkArea(Array& rc) +{ + GuiLock __; +} + +Rect Ctrl::GetVirtualWorkArea() +{ + return Rect(); +} + +Rect Ctrl::GetWorkArea(Point pt) +{ + return Rect(); +} + +Rect Ctrl::GetVirtualScreenArea() +{ + GuiLock __; + return Rect(); +} + +Rect Ctrl::GetPrimaryWorkArea() +{ + Rect r; + return Rect(); +} + +Rect Ctrl::GetPrimaryScreenArea() +{ + return Rect(); +} + +int Ctrl::GetKbdDelay() +{ + GuiLock __; + return 500; +} + +int Ctrl::GetKbdSpeed() +{ + GuiLock __; + return 1000 / 32; +} + +void Ctrl::WndDestroy0() +{ + int q = FindTopCtrl(); + if(q >= 0) { + topctrl.Remove(q); + } + if(top) { + delete top; + top = NULL; + } + isopen = false; +} + +void Ctrl::SetWndForeground0() +{ + GuiLock __; + int q = FindTopCtrl(); + if(q >= 0) { + topctrl.Remove(q); + topctrl.Add(this); + } +} + +bool Ctrl::IsWndForeground() const +{ + GuiLock __; + return false; +} + +void Ctrl::WndEnable0(bool *b) +{ + GuiLock __; +} + +void Ctrl::SetWndFocus0(bool *b) +{ + GuiLock __; + *b = true; +} + +bool Ctrl::HasWndFocus() const +{ + GuiLock __; + return focusCtrl && focusCtrl->GetTopCtrl() == this; +} + +bool Ctrl::SetWndCapture() +{ + GuiLock __; + ASSERT(IsMainThread()); + return true; +} + +bool Ctrl::ReleaseWndCapture() +{ + GuiLock __; + ASSERT(IsMainThread()); + return true; +} + +bool Ctrl::HasWndCapture() const +{ + GuiLock __; + return captureCtrl && captureCtrl->GetTopCtrl() == this; +} + +void Ctrl::WndInvalidateRect0(const Rect& r) +{ + GuiLock __; + ::InvalidateRect(glHWND, NULL, false); +} + +void Ctrl::WndSetPos0(const Rect& rect) +{ + GuiLock __; + SetWndRect(rect); +} + +void Ctrl::WndUpdate0r(const Rect& r) +{ + GuiLock __; +} + +void Ctrl::WndScrollView0(const Rect& r, int dx, int dy) +{ + GuiLock __; + Refresh(r); +} + +void Ctrl::PopUp(Ctrl *owner, bool savebits, bool activate, bool dropshadow, bool topmost) +{ + _DBG_ // Add owner management!!!! + ASSERT(!IsChild() && !IsOpen() && FindTopCtrl() < 0); + topctrl.Add(this); + popup = isopen = true; + SetTop(); + if(activate) SetFocus(); +} + +Rect Ctrl::GetDefaultWindowRect() { + return Rect(0, 0, 100, 100); +} + +Vector SplitCmdLine__(const char *cmd) +{ + Vector out; + while(*cmd) + if((byte)*cmd <= ' ') + cmd++; + else if(*cmd == '\"') { + WString quoted; + while(*++cmd && (*cmd != '\"' || *++cmd == '\"')) + quoted.Cat(FromSystemCharset(String(cmd, 1)).ToWString()); + out.Add(quoted); + } + else { + const char *begin = cmd; + while((byte)*cmd > ' ') + cmd++; + out.Add(String(begin, cmd).ToWString()); + } + return out; +} + +END_UPP_NAMESPACE + +#endif diff --git a/rainbow/WinGl/tahoma14.fnt b/rainbow/WinGl/tahoma14.fnt new file mode 100644 index 000000000..69414a0e2 --- /dev/null +++ b/rainbow/WinGl/tahoma14.fnt @@ -0,0 +1,643 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rainbow/WinGl/tahoma14.png b/rainbow/WinGl/tahoma14.png new file mode 100644 index 0000000000000000000000000000000000000000..11f6d81888a02d22ee1cf5d99b80199e301c13eb GIT binary patch literal 9684 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 I)i&aP0K?t{nE(I) literal 0 HcmV?d00001 diff --git a/rainbow/WinGl/tahoma14b.fnt b/rainbow/WinGl/tahoma14b.fnt new file mode 100644 index 000000000..2293afd05 --- /dev/null +++ b/rainbow/WinGl/tahoma14b.fnt @@ -0,0 +1,537 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rainbow/WinGl/tahoma14b.png b/rainbow/WinGl/tahoma14b.png new file mode 100644 index 0000000000000000000000000000000000000000..e04d635935981d5b399b11eacfe7fbbd9ea14a02 GIT binary patch literal 10325 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 qL6(Wid3yZx literal 0 HcmV?d00001