From 8ccf453d5ed05ed295e94058ad38bcbc3e602807 Mon Sep 17 00:00:00 2001 From: DarkWyrm Date: Tue, 28 Jan 2003 23:58:06 +0000 Subject: [PATCH] Ported and added prototype #7's ScreenDriver and ViewDriver git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2593 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/server/Desktop.cpp | 11 + src/servers/app/server/Jamfile | 2 + src/servers/app/server/ScreenDriver.cpp | 2279 +++++++++++++++++++++++ src/servers/app/server/ScreenDriver.h | 158 ++ src/servers/app/server/ServerConfig.h | 4 + src/servers/app/server/ViewDriver.cpp | 1422 ++++++++++++++ src/servers/app/server/ViewDriver.h | 170 ++ 7 files changed, 4046 insertions(+) create mode 100644 src/servers/app/server/ScreenDriver.cpp create mode 100644 src/servers/app/server/ScreenDriver.h create mode 100644 src/servers/app/server/ViewDriver.cpp create mode 100644 src/servers/app/server/ViewDriver.h diff --git a/src/servers/app/server/Desktop.cpp b/src/servers/app/server/Desktop.cpp index 6b5569db89..a9fc1f8ce9 100644 --- a/src/servers/app/server/Desktop.cpp +++ b/src/servers/app/server/Desktop.cpp @@ -26,6 +26,17 @@ //------------------------------------------------------------------------------ #include "DisplayDriver.h" #include "Desktop.h" + +#ifdef VIEWDRIVER +#include "ViewDriver.h" +#endif +#ifdef SCREENDRIVER +#include "ScreenDriver.h" +#endif +#ifdef HWDRIVER +#include "AccelerantDriver.h" +#endif + //#include "ServerWindow.h" namespace desktop_private { diff --git a/src/servers/app/server/Jamfile b/src/servers/app/server/Jamfile index e041170f13..f4e24537a7 100644 --- a/src/servers/app/server/Jamfile +++ b/src/servers/app/server/Jamfile @@ -38,8 +38,10 @@ Server app_server : Decorator.cpp DisplayDriver.cpp Layer.cpp + ScreenDriver.cpp ServerBitmap.cpp ServerCursor.cpp + ViewDriver.cpp ; LinkSharedOSLibs app_server : be root game translation libfreetype.so ; diff --git a/src/servers/app/server/ScreenDriver.cpp b/src/servers/app/server/ScreenDriver.cpp new file mode 100644 index 0000000000..7d7109905f --- /dev/null +++ b/src/servers/app/server/ScreenDriver.cpp @@ -0,0 +1,2279 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: ScreenDriver.cpp +// Author: DarkWyrm +// Description: BWindowScreen graphics module +// +//------------------------------------------------------------------------------ +#include "Angle.h" +#include "ScreenDriver.h" +#include "ServerProtocol.h" +#include "ServerBitmap.h" +#include "ServerCursor.h" +#include "ServerConfig.h" +#include "SystemPalette.h" +#include "ColorUtils.h" +#include "PortLink.h" +#include "FontFamily.h" +#include "RGBColor.h" +#include "LayerData.h" +#include +#include +#include +#include +#include + +//TODO: Remove the need for these +int64 solidhigh64=0xFFFFFFFFLL; +int8 *solidhigh=(int8*)solidhigh64; + +void HLine_32Bit(graphics_card_info i, uint16 x, uint16 y, uint16 length, rgb_color col); +void HLine_16Bit(graphics_card_info i, uint16 x, uint16 y, uint16 length, uint16 col); +void HLine_16Bit(graphics_card_info i, uint16 x, uint16 y, uint16 length, uint8 col); + +class LineCalc +{ +public: + LineCalc(const BPoint &pta, const BPoint &ptb); + float GetX(float y); + float GetY(float x); + float Slope(void) { return slope; } + float Offset(void) { return offset; } +private: + float slope; + float offset; + BPoint start, end; +}; + +LineCalc::LineCalc(const BPoint &pta, const BPoint &ptb) +{ + start=pta; + end=ptb; + slope=(start.y-end.y)/(start.x-end.x); + offset=start.y-(slope * start.x); +} + +float LineCalc::GetX(float y) +{ + return ( (y-offset)/slope ); +} + +float LineCalc::GetY(float x) +{ + return ( (slope * x) + offset ); +} + +FrameBuffer::FrameBuffer(const char *title, uint32 space, status_t *st,bool debug) + : BWindowScreen(title,space,st,debug) +{ + is_connected=false; + port_id serverport=find_port(SERVER_INPUT_PORT); + serverlink=new PortLink(serverport); + mousepos.Set(0,0); + buttons=0; +} + +FrameBuffer::~FrameBuffer(void) +{ + delete serverlink; +} + +void FrameBuffer::ScreenConnected(bool connected) +{ + is_connected=connected; + if(connected) + { + // Cache the state just in case + graphics_card_info *info=CardInfo(); + gcinfo=*info; + } +} + +void FrameBuffer::MessageReceived(BMessage *msg) +{ + switch(msg->what) + { + case B_KEY_DOWN: + { + int32 key,modifiers; + msg->FindInt32("key",&key); + msg->FindInt32("modifiers",&modifiers); + + int32 servermods=0; + servermods|=modifiers & B_RIGHT_COMMAND_KEY; + servermods|=modifiers & B_RIGHT_OPTION_KEY; + servermods|=modifiers & B_RIGHT_CONTROL_KEY; + servermods|=modifiers & B_SHIFT_KEY; + + switch(key) + { + case 0x47: // Enter key + { + port_id serverport=find_port(SERVER_PORT_NAME); + write_port(serverport,B_QUIT_REQUESTED,NULL,0); + break; + } +#ifdef ENABLE_INPUT_SERVER_EMULATION + case 0x57: // up arrow + { + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + // 5) int32 - buttons down + // 6) int32 - clicks + + + if(mousepos.y<=0) + { + mousepos.y=0; + break; + } + + uint32 clicks=1; // can't get the # of clicks without a *lot* of extra work :( + int64 time=(int64)real_time_clock(); + + if(modifiers & B_SHIFT_KEY) + mousepos.y--; + else + { + mousepos.y-=10; + if(mousepos.y<0) + mousepos.y=0; + } + + serverlink->SetOpCode(B_MOUSE_MOVED); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&mousepos.x,sizeof(float)); + serverlink->Attach(&mousepos.y,sizeof(float)); + serverlink->Attach(&servermods, sizeof(int32)); + serverlink->Attach(&buttons, sizeof(uint32)); + serverlink->Attach(&clicks, sizeof(uint32)); + serverlink->Flush(); + break; + } + case 0x62: // down arrow + { + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + // 5) int32 - buttons down + // 6) int32 - clicks + + + if(mousepos.y>= (gcinfo.height-1)) + { + mousepos.y=gcinfo.height-1; + break; + } + + uint32 clicks=1; // can't get the # of clicks without a *lot* of extra work :( + int64 time=(int64)real_time_clock(); + + if(modifiers & B_SHIFT_KEY) + mousepos.y++; + else + { + mousepos.y+=10; + if(mousepos.y>gcinfo.height-1) + mousepos.y=gcinfo.height-1; + } + + serverlink->SetOpCode(B_MOUSE_MOVED); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&mousepos.x,sizeof(float)); + serverlink->Attach(&mousepos.y,sizeof(float)); + serverlink->Attach(&servermods, sizeof(int32)); + serverlink->Attach(&buttons, sizeof(uint32)); + serverlink->Attach(&clicks, sizeof(uint32)); + serverlink->Flush(); + break; + } + case 0x61: // left arrow + { + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + // 5) int32 - buttons down + // 6) int32 - clicks + + + if(mousepos.x<=0) + { + mousepos.x=0; + break; + } + + uint32 clicks=1; // can't get the # of clicks without a *lot* of extra work :( + int64 time=(int64)real_time_clock(); + + if(modifiers & B_SHIFT_KEY) + mousepos.x--; + else + { + mousepos.x-=10; + if(mousepos.x<0) + mousepos.x=0; + } + + serverlink->SetOpCode(B_MOUSE_MOVED); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&mousepos.x,sizeof(float)); + serverlink->Attach(&mousepos.y,sizeof(float)); + serverlink->Attach(&servermods, sizeof(int32)); + serverlink->Attach(&buttons, sizeof(uint32)); + serverlink->Attach(&clicks, sizeof(uint32)); + serverlink->Flush(); + break; + } + case 0x63: // right arrow + { + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + // 5) int32 - buttons down + // 6) int32 - clicks + + + if(mousepos.x>= (gcinfo.width-1)) + { + mousepos.x=gcinfo.width-1; + break; + } + + uint32 clicks=1; // can't get the # of clicks without a *lot* of extra work :( + int64 time=(int64)real_time_clock(); + + if(modifiers & B_SHIFT_KEY) + mousepos.x++; + else + { + mousepos.x+=10; + if(mousepos.x>gcinfo.width-1) + mousepos.x=gcinfo.width-1; + } + + serverlink->SetOpCode(B_MOUSE_MOVED); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&mousepos.x,sizeof(float)); + serverlink->Attach(&mousepos.y,sizeof(float)); + serverlink->Attach(&servermods, sizeof(int32)); + serverlink->Attach(&buttons, sizeof(uint32)); + serverlink->Attach(&clicks, sizeof(uint32)); + serverlink->Flush(); + break; + } +#endif // end server emu code + default: + break; + } + } + case B_MODIFIERS_CHANGED: + { + int32 modifiers; + if(msg->FindInt32("modifiers",&modifiers)==B_OK) + { +#ifdef ENABLE_INPUT_SERVER_EMULATION + + uint32 clicks=1; // can't get the # of clicks without a *lot* of extra work :( + int64 time=(int64)real_time_clock(); + + // we need to be able to shift click & such, so we will construct + // a new modifiers value which excludes our mouse click keys + int32 servermods=0; + servermods|=modifiers & B_RIGHT_COMMAND_KEY; + servermods|=modifiers & B_RIGHT_OPTION_KEY; + servermods|=modifiers & B_RIGHT_CONTROL_KEY; + servermods|=modifiers & B_SHIFT_KEY; + + if(modifiers & B_LEFT_OPTION_KEY) + { + buttons=B_PRIMARY_MOUSE_BUTTON; + + serverlink->SetOpCode(B_MOUSE_DOWN); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&mousepos.x,sizeof(float)); + serverlink->Attach(&mousepos.y,sizeof(float)); + serverlink->Attach(&servermods, sizeof(uint32)); + serverlink->Attach(&buttons, sizeof(uint32)); + serverlink->Attach(&clicks, sizeof(uint32)); + serverlink->Flush(); + } + else + if(modifiers & B_LEFT_CONTROL_KEY) + { + buttons=B_SECONDARY_MOUSE_BUTTON; + + serverlink->SetOpCode(B_MOUSE_DOWN); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&mousepos.x,sizeof(float)); + serverlink->Attach(&mousepos.y,sizeof(float)); + serverlink->Attach(&servermods, sizeof(uint32)); + serverlink->Attach(&buttons, sizeof(uint32)); + serverlink->Attach(&clicks, sizeof(uint32)); + serverlink->Flush(); + } + else + { + // well, we got this far so none of the buttons + // are down. set our mouse buttons to up and if this + // is a change, send a B_MOUSE_UP message + if(buttons>0) + { + serverlink->SetOpCode(B_MOUSE_UP); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&mousepos.x,sizeof(float)); + serverlink->Attach(&mousepos.y,sizeof(float)); + serverlink->Attach(&servermods, sizeof(uint32)); + serverlink->Flush(); + } + buttons=0; + } +#endif // end server emu code + } + break; + } + default: + BWindowScreen::MessageReceived(msg); + } +} + +bool FrameBuffer::QuitRequested(void) +{ + port_id serverport=find_port(SERVER_PORT_NAME); + + if(serverport!=B_NAME_NOT_FOUND) + write_port(serverport,B_QUIT_REQUESTED,NULL,0); + + return true; +} + +ScreenDriver::ScreenDriver(void) : DisplayDriver() +{ + status_t st; + fbuffer=new FrameBuffer("OBAppServer",B_8_BIT_640x480,&st,true); + + drawmode = B_OP_COPY; + + cursor=NULL; + under_cursor=NULL; + cursorframe.Set(0,0,0,0); +} + +ScreenDriver::~ScreenDriver(void) +{ + if(cursor) + delete cursor; + if(under_cursor) + delete under_cursor; +} + +bool ScreenDriver::Initialize(void) +{ + fbuffer->Show(); + + // wait 1 sec for the window to show... + snooze(500000); + + // we start out without a cursor shown because otherwise we get glitches in the + // upper left corner. init_desktop *always* sets a cursor, so this shouldn't be a problem + return true; +} + +void ScreenDriver::Shutdown(void) +{ + fbuffer->Lock(); + fbuffer->Quit(); +} + +void ScreenDriver::DrawBitmap(ServerBitmap *bitmap, BRect source, BRect dest, LayerData *d) +{ + _Lock(); + if(fbuffer->IsConnected()) + { + // Scale bitmap here if source!=dest + + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 32: + case 24: + { + // TODO: Implement + printf("DrawBitmap: 32/24-bit unimplemented\n"); + break; + } + case 16: + case 15: + { + // TODO: Implement + printf("DrawBitmap: 16/15-bit unimplemented\n"); + break; + } + case 8: + { + // TODO: Implement + printf("DrawBitmap: 8-bit unimplemented\n"); + break; + } + default: + { + break; + } + } + } + + _Unlock(); +} + +// Ellipse code shamelessly stolen from the graphics library gd v2.0.1 and bolted on +// to support our API +void ScreenDriver::FillEllipse(BRect r, LayerData *ldata, int8 *pat) +{ + long d, b_sq, b_sq_4, b_sq_6; + long a_sq, a_sq_4, a_sq_6; + int x, y, switchem; + long lsqrt (long); + int pix, half, pstart; + int32 thick = (int32)ldata->pensize; + + half = thick / 2; + int32 w=int32(r.Width()/2), + h=int32(r.Height()/2); + int32 cx=(int32)r.left+w; + int32 cy=(int32)r.top+h; + + d = 2 * (long) h *h + (long) w *w - 2 * (long) w *w * h; + b_sq = (long) h *h; + b_sq_4 = 4 * (long) h *h; + b_sq_6 = 6 * (long) h *h; + a_sq = (long) w *w; + a_sq_4 = 4 * (long) w *w; + a_sq_6 = 6 * (long) w *w; + + x = 0; + y = -h; +// switchem = a_sq / lsqrt (a_sq + b_sq); + switchem = a_sq / (int32)sqrt(a_sq + b_sq); + + while (x <= switchem) + { + pstart = y - half; + for (pix = pstart; pix < pstart + thick; pix++) + { + Line( BPoint(cx - x, cy + pix), BPoint(cx + x, cy + pix), ldata, solidhigh); + Line( BPoint(cx - x, cy - pix), BPoint(cx + x, cy - pix), ldata, solidhigh); + } + if (d < 0) + d += b_sq_4 * x++ + b_sq_6; + else + d += b_sq_4 * x++ + b_sq_6 + a_sq_4 * (++y); + } + + /* Middlesplat! + ** Go a little further if the thickness is not nominal... + */ + if (thick > 1) + { + int xp = x; + int yp = y; + int dp = d; + int thick2 = thick + 2; + int half2 = half + 1; + + while (xp <= switchem + half) + { + pstart = yp - half2; + for (pix = pstart; pix < pstart + thick2; pix++) + { + Line( BPoint(cx - xp, cy + pix), BPoint(cx + xp, cy + pix), ldata, solidhigh); + Line( BPoint(cx - xp, cy - pix), BPoint(cx + xp, cy - pix), ldata, solidhigh); + } + if (dp < 0) + dp += b_sq_4 * xp++ + b_sq_6; + else + dp += b_sq_4 * xp++ + b_sq_6 + a_sq_4 * (++yp); + } + } + + d += -2 * (long) b_sq + 2 * (long) a_sq - 2 * (long) b_sq *(x - 1) + 2 * (long) a_sq *(y - 1); + + while (y <= 0) + { + pstart = x - half; + for (pix = pstart; pix < pstart + thick; pix++) + { + Line( BPoint(cx - pix, cy + y), BPoint(cx + pix, cy + y), ldata, solidhigh); + Line( BPoint(cx - pix, cy - y), BPoint(cx + pix, cy - y), ldata, solidhigh); + } + + if (d < 0) + d += a_sq_4 * y++ + a_sq_6 + b_sq_4 * (++x); + else + d += a_sq_4 * y++ + a_sq_6; + } +} + +void ScreenDriver::FillRect(BRect r, LayerData *d, int8 *pat) +{ + _Lock(); + if(fbuffer->IsConnected()) + { + // int32 width=rect.IntegerWidth(); + for(int32 i=(int32)r.top;i<=r.bottom;i++) + // HLine(fbuffer->gcinfo,(int32)rect.left,i,width,col); + Line(BPoint(r.left,i),BPoint(r.right,i),d,pat); + } + _Unlock(); +} + +void ScreenDriver::FillRoundRect(BRect r, float xrad, float yrad, LayerData *d, int8 *pat) +{ + FillRect(r,d,pat); +} + +void ScreenDriver::FillTriangle(BPoint *pts, BRect r, LayerData *d, int8 *pat) +{ + if(!pts || !d || !pat) + return; + + _Lock(); + if(fbuffer->IsConnected()) + { + BPoint first, second, third; + + // Sort points according to their y values + if(pts[0].y < pts[1].y) + { + first=pts[0]; + second=pts[1]; + } + else + { + first=pts[1]; + second=pts[0]; + } + + if(second.ygcinfo.bits_per_pixel) + { + case 32: + case 24: + SetThickPixel32(x,y,thick,col.GetColor32()); + break; + case 16: + case 15: + SetThickPixel16(x,y,thick,col.GetColor16()); + break; + case 8: + SetThickPixel8(x,y,thick,col.GetColor8()); + break; + default: + printf("Unknown pixel depth %d in SetThickPixel\n",fbuffer->gcinfo.bits_per_pixel); + break; + } +} + +void ScreenDriver::SetThickPixel32(int x, int y, int thick, rgb_color col) +{ + // Code courtesy of YNOP's SecondDriver + union + { + uint8 bytes[4]; + uint32 word; + }c1; + + c1.bytes[0]=col.blue; + c1.bytes[1]=col.green; + c1.bytes[2]=col.red; + c1.bytes[3]=col.alpha; + + /* + uint32 *bits=(uint32*)fbuffer->gcinfo.frame_buffer; + *(bits + x + (y*fbuffer->gcinfo.width))=c1.word; + */ + uint32 *bits=(uint32*)fbuffer->gcinfo.frame_buffer+(x-thick/2)+(y-thick/2)*fbuffer->gcinfo.width; + int i,j; + for (i=0; igcinfo.width; + } +} + +void ScreenDriver::SetThickPixel16(int x, int y, int thick, uint16 col) +{ +// TODO: Implement +printf("SetThickPixel16 unimplemented\n"); + +} + +void ScreenDriver::SetThickPixel8(int x, int y, int thick, uint8 col) +{ + // When the DisplayDriver API changes, we'll use the uint8 highcolor. Until then, + // we'll use *pattern + /* + uint8 *bits=(uint8*)fbuffer->gcinfo.frame_buffer; + *(bits + x + (y*fbuffer->gcinfo.bytes_per_row))=col; + */ + + uint8 *bits=(uint8*)fbuffer->gcinfo.frame_buffer+(x-thick/2)+(y-thick/2)*fbuffer->gcinfo.bytes_per_row; + int i,j; + for (i=0; igcinfo.bytes_per_row; + } +} + +void ScreenDriver::SetPixel(int x, int y, RGBColor col) +{ + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 32: + case 24: + SetPixel32(x,y,col.GetColor32()); + break; + case 16: + case 15: + SetPixel16(x,y,col.GetColor16()); + break; + case 8: + SetPixel8(x,y,col.GetColor8()); + break; + default: + break; + } +} + +void ScreenDriver::SetPixel32(int x, int y, rgb_color col) +{ + // Code courtesy of YNOP's SecondDriver + union + { + uint8 bytes[4]; + uint32 word; + }c1; + + c1.bytes[0]=col.blue; + c1.bytes[1]=col.green; + c1.bytes[2]=col.red; + c1.bytes[3]=col.alpha; + + uint32 *bits=(uint32*)fbuffer->gcinfo.frame_buffer; + *(bits + x + (y*fbuffer->gcinfo.width))=c1.word; +} + +void ScreenDriver::SetPixel16(int x, int y, uint16 col) +{ +// TODO: Implement +printf("SetPixel16 unimplemented\n"); + +} + +void ScreenDriver::SetPixel8(int x, int y, uint8 col) +{ + // When the DisplayDriver API changes, we'll use the uint8 highcolor. Until then, + // we'll use *pattern + uint8 *bits=(uint8*)fbuffer->gcinfo.frame_buffer; + *(bits + x + (y*fbuffer->gcinfo.bytes_per_row))=col; + +} + +void ScreenDriver::SetMode(int32 space) +{ + _Lock(); + if(fbuffer->IsConnected()) + { + fbuffer->SetSpace(space); + + // We have changed the frame buffer info, so update the cached info + graphics_card_info *info=fbuffer->CardInfo(); + fbuffer->gcinfo=*info; + + // clear the frame buffer. Otherwise, we'll have garbage in it + LayerData d; + d.highcolor.SetColor(80,85,152); + for(int32 i=0; iheight; i++) + { + Line(BPoint(0,i),BPoint(info->width-1,i),&d,solidhigh); + } + } + _Unlock(); +} + + +// Currently does not support pattern +void ScreenDriver::StrokeArc(BRect r, float angle, float span, LayerData *d, int8 *pat) +{ + float xc = (r.left+r.right)/2; + float yc = (r.top+r.bottom)/2; + float rx = r.Width()/2; + float ry = r.Height()/2; + int Rx2 = ROUND(rx*rx); + int Ry2 = ROUND(ry*ry); + int twoRx2 = 2*Rx2; + int twoRy2 = 2*Ry2; + int p; + int x=0; + int y = (int)ry; + int px = 0; + int py = twoRx2 * y; + int startx, endx; + int startQuad, endQuad; + bool useQuad1, useQuad2, useQuad3, useQuad4; + bool shortspan = false; + int thick = (int)d->pensize; + + // Watch out for bozos giving us whacko spans + if ( (span >= 360) || (span <= -360) ) + { + StrokeEllipse(r,d,pat); + return; + } + + if ( span > 0 ) + { + startQuad = (int)(angle/90)%4+1; + endQuad = (int)((angle+span)/90)%4+1; + startx = ROUND(.5*r.Width()*fabs(cos(angle*M_PI/180))); + endx = ROUND(.5*r.Width()*fabs(cos((angle+span)*M_PI/180))); + } + else + { + endQuad = (int)(angle/90)%4+1; + startQuad = (int)((angle+span)/90)%4+1; + endx = ROUND(.5*r.Width()*fabs(cos(angle*M_PI/180))); + startx = ROUND(.5*r.Width()*fabs(cos((angle+span)*M_PI/180))); + } + + if ( startQuad != endQuad ) + { + useQuad1 = (endQuad > 1) && (startQuad > endQuad); + useQuad2 = ((startQuad == 1) && (endQuad > 2)) || ((startQuad > endQuad) && (endQuad > 2)); + useQuad3 = ((startQuad < 3) && (endQuad == 4)) || ((startQuad < 3) && (endQuad < startQuad)); + useQuad4 = (startQuad < 4) && (startQuad > endQuad); + } + else + { + if ( (span < 90) && (span > -90) ) + { + useQuad1 = false; + useQuad2 = false; + useQuad3 = false; + useQuad4 = false; + shortspan = true; + } + else + { + useQuad1 = (startQuad != 1); + useQuad2 = (startQuad != 2); + useQuad3 = (startQuad != 3); + useQuad4 = (startQuad != 4); + } + } + + if ( useQuad1 || + (!shortspan && (((startQuad == 1) && (x <= startx)) || ((endQuad == 1) && (x >= endx)))) || + (shortspan && (startQuad == 1) && (x <= startx) && (x >= endx)) ) + SetThickPixel(xc+x,yc-y,thick,d->highcolor); + if ( useQuad2 || + (!shortspan && (((startQuad == 2) && (x >= startx)) || ((endQuad == 2) && (x <= endx)))) || + (shortspan && (startQuad == 2) && (x >= startx) && (x <= endx)) ) + SetThickPixel(xc-x,yc-y,thick,d->highcolor); + if ( useQuad3 || + (!shortspan && (((startQuad == 3) && (x <= startx)) || ((endQuad == 3) && (x >= endx)))) || + (shortspan && (startQuad == 3) && (x <= startx) && (x >= endx)) ) + SetThickPixel(xc-x,yc+y,thick,d->highcolor); + if ( useQuad4 || + (!shortspan && (((startQuad == 4) && (x >= startx)) || ((endQuad == 4) && (x <= endx)))) || + (shortspan && (startQuad == 4) && (x >= startx) && (x <= endx)) ) + SetThickPixel(xc+x,yc+y,thick,d->highcolor); + + p = ROUND (Ry2 - (Rx2 * ry) + (.25 * Rx2)); + while (px < py) + { + x++; + px += twoRy2; + if ( p < 0 ) + p += Ry2 + px; + else + { + y--; + py -= twoRx2; + p += Ry2 + px - py; + } + + if ( useQuad1 || + (!shortspan && (((startQuad == 1) && (x <= startx)) || ((endQuad == 1) && (x >= endx)))) || + (shortspan && (startQuad == 1) && (x <= startx) && (x >= endx)) ) + SetThickPixel(xc+x,yc-y,thick,d->highcolor); + if ( useQuad2 || + (!shortspan && (((startQuad == 2) && (x >= startx)) || ((endQuad == 2) && (x <= endx)))) || + (shortspan && (startQuad == 2) && (x >= startx) && (x <= endx)) ) + SetThickPixel(xc-x,yc-y,thick,d->highcolor); + if ( useQuad3 || + (!shortspan && (((startQuad == 3) && (x <= startx)) || ((endQuad == 3) && (x >= endx)))) || + (shortspan && (startQuad == 3) && (x <= startx) && (x >= endx)) ) + SetThickPixel(xc-x,yc+y,thick,d->highcolor); + if ( useQuad4 || + (!shortspan && (((startQuad == 4) && (x >= startx)) || ((endQuad == 4) && (x <= endx)))) || + (shortspan && (startQuad == 4) && (x >= startx) && (x <= endx)) ) + SetThickPixel(xc+x,yc+y,thick,d->highcolor); + } + + p = ROUND(Ry2*(x+.5)*(x+.5) + Rx2*(y-1)*(y-1) - Rx2*Ry2); + while (y>0) + { + y--; + py -= twoRx2; + if (p>0) + p += Rx2 - py; + else + { + x++; + px += twoRy2; + p += Rx2 - py +px; + } + + if ( useQuad1 || + (!shortspan && (((startQuad == 1) && (x <= startx)) || ((endQuad == 1) && (x >= endx)))) || + (shortspan && (startQuad == 1) && (x <= startx) && (x >= endx)) ) + SetThickPixel(xc+x,yc-y,thick,d->highcolor); + if ( useQuad2 || + (!shortspan && (((startQuad == 2) && (x >= startx)) || ((endQuad == 2) && (x <= endx)))) || + (shortspan && (startQuad == 2) && (x >= startx) && (x <= endx)) ) + SetThickPixel(xc-x,yc-y,thick,d->highcolor); + if ( useQuad3 || + (!shortspan && (((startQuad == 3) && (x <= startx)) || ((endQuad == 3) && (x >= endx)))) || + (shortspan && (startQuad == 3) && (x <= startx) && (x >= endx)) ) + SetThickPixel(xc-x,yc+y,thick,d->highcolor); + if ( useQuad4 || + (!shortspan && (((startQuad == 4) && (x >= startx)) || ((endQuad == 4) && (x <= endx)))) || + (shortspan && (startQuad == 4) && (x >= startx) && (x <= endx)) ) + SetThickPixel(xc+x,yc+y,thick,d->highcolor); + } +} + +// Currently does not support pattern +void ScreenDriver::StrokeBezier(BPoint *pts, LayerData *d, int8 *pat) +{ + double Ax, Bx, Cx, Dx; + double Ay, By, Cy, Dy; + int x, y; + int lastx=-1, lasty=-1; + double t; + double dt = .001; + double dt2, dt3; + double X, Y, dx, ddx, dddx, dy, ddy, dddy; + + Ax = -pts[0].x + 3*pts[1].x - 3*pts[2].x + pts[3].x; + Bx = 3*pts[0].x - 6*pts[1].x + 3*pts[2].x; + Cx = -3*pts[0].x + 3*pts[1].x; + Dx = pts[0].x; + + Ay = -pts[0].y + 3*pts[1].y - 3*pts[2].y + pts[3].y; + By = 3*pts[0].y - 6*pts[1].y + 3*pts[2].y; + Cy = -3*pts[0].y + 3*pts[1].y; + Dy = pts[0].y; + + dt2 = dt * dt; + dt3 = dt2 * dt; + X = Dx; + dx = Ax*dt3 + Bx*dt2 + Cx*dt; + ddx = 6*Ax*dt3 + 2*Bx*dt2; + dddx = 6*Ax*dt3; + Y = Dy; + dy = Ay*dt3 + By*dt2 + Cy*dt; + ddy = 6*Ay*dt3 + 2*By*dt2; + dddy = 6*Ay*dt3; + + lastx = -1; + lasty = -1; + + for (t=0; t<=1; t+=dt) + { + x = ROUND(X); + y = ROUND(Y); + if ( (x!=lastx) || (y!=lasty) ) + SetThickPixel(x,y,d->pensize,d->highcolor); + lastx = x; + lasty = y; + + X += dx; + dx += ddx; + ddx += dddx; + Y += dy; + dy += ddy; + ddy += dddy; + } +} + +// Ellipse code shamelessly stolen from the graphics library gd v2.0.1 and bolted on +// to support our API +void ScreenDriver::StrokeEllipse(BRect r, LayerData *ldata, int8 *pat) +{ + long d, b_sq, b_sq_4, b_sq_6; + long a_sq, a_sq_4, a_sq_6; + int x, y, switchem; + long lsqrt (long); + int pix, half, pstart; + int32 thick = (int32)ldata->pensize; + + half = thick / 2; + int32 w=int32(r.Width()/2), + h=int32(r.Height()/2); + int32 cx=(int32)r.left+w; + int32 cy=(int32)r.top+h; + + d = 2 * (long) h *h + (long) w *w - 2 * (long) w *w * h; + b_sq = (long) h *h; + b_sq_4 = 4 * (long) h *h; + b_sq_6 = 6 * (long) h *h; + a_sq = (long) w *w; + a_sq_4 = 4 * (long) w *w; + a_sq_6 = 6 * (long) w *w; + + x = 0; + y = -h; +// switchem = a_sq / lsqrt (a_sq + b_sq); + switchem = a_sq / (int32)sqrt(a_sq + b_sq); + + while (x <= switchem) + { + pstart = y - half; + for (pix = pstart; pix < pstart + thick; pix++) + { + SetPixel(cx + x, cy + pix, ldata->highcolor); + SetPixel(cx - x, cy + pix, ldata->highcolor); + SetPixel(cx + x, cy - pix, ldata->highcolor); + SetPixel(cx - x, cy - pix, ldata->highcolor); + } + if (d < 0) + d += b_sq_4 * x++ + b_sq_6; + else + d += b_sq_4 * x++ + b_sq_6 + a_sq_4 * (++y); + } + + /* Middlesplat! + ** Go a little further if the thickness is not nominal... + */ + if (thick > 1) + { + int xp = x; + int yp = y; + int dp = d; + int thick2 = thick + 2; + int half2 = half + 1; + + while (xp <= switchem + half) + { + pstart = yp - half2; + for (pix = pstart; pix < pstart + thick2; pix++) + { + SetPixel(cx + xp, cy + pix, ldata->highcolor); + SetPixel(cx - xp, cy + pix, ldata->highcolor); + SetPixel(cx + xp, cy - pix, ldata->highcolor); + SetPixel(cx - xp, cy - pix, ldata->highcolor); + } + if (dp < 0) + dp += b_sq_4 * xp++ + b_sq_6; + else + dp += b_sq_4 * xp++ + b_sq_6 + a_sq_4 * (++yp); + } + } + + d += -2 * (long) b_sq + 2 * (long) a_sq - 2 * (long) b_sq *(x - 1) + 2 * (long) a_sq *(y - 1); + + while (y <= 0) + { + pstart = x - half; + for (pix = pstart; pix < pstart + thick; pix++) + { + SetPixel (cx + pix, cy + y, ldata->highcolor); + SetPixel (cx - pix, cy + y, ldata->highcolor); + SetPixel (cx + pix, cy - y, ldata->highcolor); + SetPixel (cx - pix, cy - y, ldata->highcolor); + } + + if (d < 0) + d += a_sq_4 * y++ + a_sq_6 + b_sq_4 * (++x); + else + d += a_sq_4 * y++ + a_sq_6; + } + +} + +void ScreenDriver::StrokeLine(BPoint start, BPoint end, LayerData *d, int8 *pat) +{ + _Lock(); + if(fbuffer->IsConnected()) + { + // Courtesy YNOP's SecondDriver with minor changes by DW + int oct=0; + int xoff=(int32)end.x; + int yoff=(int32)end.y; + int32 x2=(int32)start.x-xoff; + int32 y2=(int32)start.y-yoff; + int32 x1=0; + int32 y1=0; + if(y2<0){ y2=-y2; oct+=4; }//bit2=1 + if(x2<0){ x2=-x2; oct+=2;}//bit1=1 + if(x2highcolor);break; + case 1:SetPixel(( y)+xoff,( x)+yoff,d->highcolor);break; + case 3:SetPixel((-y)+xoff,( x)+yoff,d->highcolor);break; + case 2:SetPixel((-x)+xoff,( y)+yoff,d->highcolor);break; + case 6:SetPixel((-x)+xoff,(-y)+yoff,d->highcolor);break; + case 7:SetPixel((-y)+xoff,(-x)+yoff,d->highcolor);break; + case 5:SetPixel(( y)+xoff,(-x)+yoff,d->highcolor);break; + case 4:SetPixel(( x)+xoff,(-y)+yoff,d->highcolor);break; + } + x++; + sum-=Dy; + if(sum < 0) + { + y++; + sum += Dx; + } + } + } + _Unlock(); +} + +void ScreenDriver::StrokePolygon(BPoint *ptlist, int32 numpts, BRect rect, LayerData *d, int8 *pat, bool is_closed=true) +{ + _Lock(); + if(fbuffer->IsConnected()) + { + for(int32 i=0; i<(numpts-1); i++) + Line(ptlist[i],ptlist[i+1],d,pat); + + if(is_closed) + Line(ptlist[numpts-1],ptlist[0],d,pat); + } + _Unlock(); +} + +void ScreenDriver::StrokeRect(BRect r, LayerData *d, int8 *pat) +{ + _Lock(); + if(fbuffer->IsConnected()) + { + Line(r.LeftTop(),r.RightTop(),d,pat); + Line(r.RightTop(),r.RightBottom(),d,pat); + Line(r.RightBottom(),r.LeftBottom(),d,pat); + Line(r.LeftTop(),r.LeftBottom(),d,pat); + } + _Unlock(); +} + +void ScreenDriver::StrokeRoundRect(BRect r, float xrad, float yrad, LayerData *d, int8 *pat) +{ +// TODO: Implement +printf("ScreenDriver::StrokeRoundRect( (%f,%f,%f,%f), %llx) ---->Unimplemented<----\n",r.left,r.top, + r.right,r.bottom,*((uint64*)pat)); + StrokeRect(r,d,pat); +} + +void ScreenDriver::StrokeTriangle(BPoint *pts, BRect r, LayerData *d, int8 *pat) +{ + _Lock(); + if(fbuffer->IsConnected()) + { + Line(pts[0],pts[1],d,pat); + Line(pts[1],pts[2],d,pat); + Line(pts[2],pts[0],d,pat); + } + _Unlock(); +} + +void ScreenDriver::SetPixelPattern(int x, int y, uint8 *pattern, uint8 patternindex) +{ + // This function is designed to add pattern support to this thing. Should be + // inlined later to add speed lost in the multiple function calls. + if(patternindex>32) + return; + + if(fbuffer->IsConnected()) + { + uint64 *p64=(uint64*)pattern; + + // check for transparency in mask. If transparent, we can quit here + + bool transparent_bit= + ( *p64 & ~((uint64)2 << (32-patternindex)))?true:false; + +// bool highcolor_bit= +// ( *p64 & ~((uint64)2 << (64-patternindex)))?true:false; + + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 32: + case 24: + { + + break; + } + case 16: + case 15: + { + break; + } + case 8: + { + break; + } + default: + { + break; + } + } + } +} + +void ScreenDriver::Line(BPoint start, BPoint end, LayerData *d, int8 *pat) +{ + // Internal function which is called from within other functions + + // Courtesy YNOP's SecondDriver with minor changes by DW + int oct=0; + int xoff=(int32)end.x; + int yoff=(int32)end.y; + int32 x2=(int32)start.x-xoff; + int32 y2=(int32)start.y-yoff; + int32 x1=0; + int32 y1=0; + if(y2<0){ y2=-y2; oct+=4; }//bit2=1 + if(x2<0){ x2=-x2; oct+=2;}//bit1=1 + if(x2highcolor);break; + case 1:SetPixel(( y)+xoff,( x)+yoff,d->highcolor);break; + case 3:SetPixel((-y)+xoff,( x)+yoff,d->highcolor);break; + case 2:SetPixel((-x)+xoff,( y)+yoff,d->highcolor);break; + case 6:SetPixel((-x)+xoff,(-y)+yoff,d->highcolor);break; + case 7:SetPixel((-y)+xoff,(-x)+yoff,d->highcolor);break; + case 5:SetPixel(( y)+xoff,(-x)+yoff,d->highcolor);break; + case 4:SetPixel(( x)+xoff,(-y)+yoff,d->highcolor);break; + } + x++; + sum-=Dy; + if(sum < 0) + { + y++; + sum += Dx; + } + } +} + +void ScreenDriver::HideCursor(void) +{ + _Lock(); + if(fbuffer->IsConnected()) + { + if(!IsCursorHidden()) + BlitBitmap(under_cursor,under_cursor->Bounds(),cursorframe, B_OP_COPY); + DisplayDriver::HideCursor(); + + } + _Unlock(); +} + +void ScreenDriver::MoveCursorTo(float x, float y) +{ + _Lock(); + if(!IsCursorHidden()) + BlitBitmap(under_cursor,under_cursor->Bounds(),cursorframe, B_OP_COPY); + + cursorframe.OffsetTo(x,y); + ExtractToBitmap(under_cursor,under_cursor->Bounds(),cursorframe); + + if(!IsCursorHidden()) + BlitBitmap(cursor,cursor->Bounds(),cursorframe, B_OP_OVER); + + _Unlock(); +} + +void ScreenDriver::ShowCursor(void) +{ + _Lock(); + if(fbuffer->IsConnected()) + { + if(IsCursorHidden()) + BlitBitmap(cursor,cursor->Bounds(),cursorframe, B_OP_OVER); + DisplayDriver::ShowCursor(); + } + _Unlock(); +} + +void ScreenDriver::ObscureCursor(void) +{ + _Lock(); + if(!IsCursorHidden() && fbuffer->IsConnected()) + BlitBitmap(under_cursor,under_cursor->Bounds(),cursorframe, B_OP_COPY); + DisplayDriver::ObscureCursor(); + _Unlock(); +} + +void ScreenDriver::SetCursor(ServerCursor *csr) +{ + if(!csr) + return; + + _Lock(); + + // erase old if visible + if(!IsCursorHidden() && under_cursor) + BlitBitmap(under_cursor,under_cursor->Bounds(),cursorframe, B_OP_COPY); + + if(cursor) + delete cursor; + if(under_cursor) + delete under_cursor; + + cursor=new ServerCursor(csr); + under_cursor=new ServerCursor(csr); + + cursorframe.right=cursorframe.left+csr->Bounds().Width(); + cursorframe.bottom=cursorframe.top+csr->Bounds().Height(); + + ExtractToBitmap(under_cursor,under_cursor->Bounds(),cursorframe); + + if(!IsCursorHidden()) + BlitBitmap(cursor,cursor->Bounds(),cursorframe, B_OP_OVER); + + _Unlock(); +} + +void ScreenDriver::HLine(int32 x1, int32 x2, int32 y, RGBColor color) +{ + // Internal function called from others in the driver + + // TODO: Implement and substitute Line() calls with HLine calls as appropriate + // elsewhere in the driver + + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 32: + case 24: + break; + case 16: + case 15: + break; + default: + break; + } +} + +void HLine_32Bit(graphics_card_info i, uint16 x, uint16 y, uint16 length, rgb_color col) +{ +// TODO: Finish +printf("HLine32() Unfinished\n"); + uint32 c=0,*pcolor,bytes; + + // apparently width=bytes per row + uint32 bpr=i.width; + + // ARGB order + c|=col.alpha * 0x01000000; + c|=col.red * 0x010000; + c|=col.green * 0x0100; + c|=col.blue; + + bytes=(uint32(x+length)>bpr)?length-((x+length)-bpr):length; + + pcolor=(uint32*)i.frame_buffer; + pcolor+=(y*bpr)+(x*4); + for(int32 i=0;ibpr)?length-((x+length)-bpr):length; + + memset(pcolor,col,bytes); +} + +// This function is intended to eventually take care of most of the heavy lifting for +// DrawBitmap in 32-bit mode, with others coming later. Right now, it is *just* used for +// the +void ScreenDriver::BlitBitmap(ServerBitmap *sourcebmp,BRect sourcerect, BRect destrect, drawing_mode mode=B_OP_COPY) +{ + // Another internal function called from other functions. + + if(!sourcebmp) + return; + + if(sourcebmp->BitsPerPixel() != fbuffer->gcinfo.bits_per_pixel) + return; + + uint8 colorspace_size=sourcebmp->BitsPerPixel()/8; + // First, clip source rect to destination + if(sourcerect.Width() > destrect.Width()) + sourcerect.right=sourcerect.left+destrect.Width(); + + + if(sourcerect.Height() > destrect.Height()) + sourcerect.bottom=sourcerect.top+destrect.Height(); + + + // Second, check rectangle bounds against their own bitmaps + BRect work_rect; + + work_rect.Set( sourcebmp->Bounds().left, + sourcebmp->Bounds().top, + sourcebmp->Bounds().right, + sourcebmp->Bounds().bottom ); + if( !(work_rect.Contains(sourcerect)) ) + { // something in selection must be clipped + if(sourcerect.left < 0) + sourcerect.left = 0; + if(sourcerect.right > work_rect.right) + sourcerect.right = work_rect.right; + if(sourcerect.top < 0) + sourcerect.top = 0; + if(sourcerect.bottom > work_rect.bottom) + sourcerect.bottom = work_rect.bottom; + } + + work_rect.Set( 0,0,fbuffer->gcinfo.width-1,fbuffer->gcinfo.height-1); + + if( !(work_rect.Contains(destrect)) ) + { // something in selection must be clipped + if(destrect.left < 0) + destrect.left = 0; + if(destrect.right > work_rect.right) + destrect.right = work_rect.right; + if(destrect.top < 0) + destrect.top = 0; + if(destrect.bottom > work_rect.bottom) + destrect.bottom = work_rect.bottom; + } + + // Set pointers to the actual data + uint8 *src_bits = (uint8*) sourcebmp->Bits(); + uint8 *dest_bits = (uint8*) fbuffer->gcinfo.frame_buffer; + + // Get row widths for offset looping + uint32 src_width = uint32 (sourcebmp->BytesPerRow()); + uint32 dest_width = uint32 (fbuffer->gcinfo.bytes_per_row); + + // Offset bitmap pointers to proper spot in each bitmap + src_bits += uint32 ( (sourcerect.top * src_width) + (sourcerect.left * colorspace_size) ); + dest_bits += uint32 ( (destrect.top * dest_width) + (destrect.left * colorspace_size) ); + + uint32 line_length = uint32 ((destrect.right - destrect.left+1)*colorspace_size); + uint32 lines = uint32 (destrect.bottom-destrect.top+1); + + switch(mode) + { + case B_OP_OVER: + { + uint32 srow_pixels=src_width>>2; + uint8 *srow_index, *drow_index; + + + // This could later be optimized to use uint32's for faster copying + for (uint32 pos_y=0; pos_y!=lines; pos_y++) + { + + srow_index=src_bits; + drow_index=dest_bits; + + for(uint32 pos_x=0; pos_x!=srow_pixels;pos_x++) + { + // 32-bit RGBA32 mode byte order is BGRA + if(srow_index[3]>127) + { + *drow_index=*srow_index; drow_index++; srow_index++; + *drow_index=*srow_index; drow_index++; srow_index++; + *drow_index=*srow_index; drow_index++; srow_index++; + // we don't copy the alpha channel + drow_index++; srow_index++; + } + else + { + srow_index+=4; + drow_index+=4; + } + } + + // Increment offsets + src_bits += src_width; + dest_bits += dest_width; + } + break; + } + default: // B_OP_COPY + { + for (uint32 pos_y = 0; pos_y != lines; pos_y++) + { + memcpy(dest_bits,src_bits,line_length); + + // Increment offsets + src_bits += src_width; + dest_bits += dest_width; + } + break; + } + } +} + +void ScreenDriver::ExtractToBitmap(ServerBitmap *destbmp,BRect destrect, BRect sourcerect) +{ + // Another internal function called from other functions. Extracts data from + // the framebuffer to a target ServerBitmap + + if(!destbmp) + return; + + if(destbmp->BitsPerPixel() != fbuffer->gcinfo.bits_per_pixel) + return; + + uint8 colorspace_size=destbmp->BitsPerPixel()/8; + // First, clip source rect to destination + if(sourcerect.Width() > destrect.Width()) + sourcerect.right=sourcerect.left+destrect.Width(); + + + if(sourcerect.Height() > destrect.Height()) + sourcerect.bottom=sourcerect.top+destrect.Height(); + + + // Second, check rectangle bounds against their own bitmaps + BRect work_rect; + + work_rect.Set( destbmp->Bounds().left, + destbmp->Bounds().top, + destbmp->Bounds().right, + destbmp->Bounds().bottom ); + if( !(work_rect.Contains(destrect)) ) + { // something in selection must be clipped + if(destrect.left < 0) + destrect.left = 0; + if(destrect.right > work_rect.right) + destrect.right = work_rect.right; + if(destrect.top < 0) + destrect.top = 0; + if(destrect.bottom > work_rect.bottom) + destrect.bottom = work_rect.bottom; + } + + work_rect.Set( 0,0,fbuffer->gcinfo.width-1,fbuffer->gcinfo.height-1); + + if( !(work_rect.Contains(sourcerect)) ) + { // something in selection must be clipped + if(sourcerect.left < 0) + sourcerect.left = 0; + if(sourcerect.right > work_rect.right) + sourcerect.right = work_rect.right; + if(sourcerect.top < 0) + sourcerect.top = 0; + if(sourcerect.bottom > work_rect.bottom) + sourcerect.bottom = work_rect.bottom; + } + + // Set pointers to the actual data + uint8 *dest_bits = (uint8*) destbmp->Bits(); + uint8 *src_bits = (uint8*) fbuffer->gcinfo.frame_buffer; + + // Get row widths for offset looping + uint32 dest_width = uint32 (destbmp->BytesPerRow()); + uint32 src_width = uint32 (fbuffer->gcinfo.bytes_per_row); + + // Offset bitmap pointers to proper spot in each bitmap + src_bits += uint32 ( (sourcerect.top * src_width) + (sourcerect.left * colorspace_size) ); + dest_bits += uint32 ( (destrect.top * dest_width) + (destrect.left * colorspace_size) ); + + uint32 line_length = uint32 ((destrect.right - destrect.left+1)*colorspace_size); + uint32 lines = uint32 (destrect.bottom-destrect.top+1); + + for (uint32 pos_y = 0; pos_y != lines; pos_y++) + { + memcpy(dest_bits,src_bits,line_length); + + // Increment offsets + src_bits += src_width; + dest_bits += dest_width; + } +} + +void ScreenDriver::InvertRect(BRect r) +{ + _Lock(); + if(fbuffer->IsConnected()) + { + if(r.top<0 || r.left<0 || + r.right>fbuffer->gcinfo.width-1 || r.bottom>fbuffer->gcinfo.height-1) + { + _Unlock(); + return; + } + + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 32: + case 24: + { + uint16 width=r.IntegerWidth(), height=r.IntegerHeight(); + uint32 *start=(uint32*)fbuffer->gcinfo.frame_buffer, *index; + start+=int32(r.top)*fbuffer->gcinfo.width; + start+=int32(r.left); + + for(int32 i=0;igcinfo.width); + for(int32 j=0; jfont) + return 0.0; + _Lock(); + + ServerFont *font=d->font; + FontStyle *style=font->Style(); + + if(!style) + { + _Unlock(); + return 0.0; + } + + FT_Face face; + FT_GlyphSlot slot; + FT_UInt glyph_index, previous=0; + FT_Vector pen,delta; + int16 error=0; + int32 strlength,i; + float returnval; + + error=FT_New_Face(ftlib, style->GetPath(), 0, &face); + if(error) + { + _Unlock(); + return 0.0; + } + + slot=face->glyph; + + bool use_kerning=FT_HAS_KERNING(face) && font->Spacing()==B_STRING_SPACING; + + error=FT_Set_Char_Size(face, 0,int32(font->Size())*64,72,72); + if(error) + { + _Unlock(); + return 0.0; + } + + // set the pen position in 26.6 cartesian space coordinates + pen.x=0; + + slot=face->glyph; + + strlength=strlen(string); + if(lengthadvance.x; + previous=glyph_index; + } + + FT_Done_Face(face); + + returnval=pen.x>>6; + _Unlock(); + return returnval; +} + +float ScreenDriver::StringHeight(const char *string, int32 length, LayerData *d) +{ + if(!string || !d || !d->font) + return 0.0; + _Lock(); + + ServerFont *font=d->font; + FontStyle *style=font->Style(); + + if(!style) + { + _Unlock(); + return 0.0; + } + + FT_Face face; + FT_GlyphSlot slot; + int16 error=0; + int32 strlength,i; + float returnval=0.0,ascent=0.0,descent=0.0; + + error=FT_New_Face(ftlib, style->GetPath(), 0, &face); + if(error) + { + _Unlock(); + return 0.0; + } + + slot=face->glyph; + + error=FT_Set_Char_Size(face, 0,int32(font->Size())*64,72,72); + if(error) + { + _Unlock(); + return 0.0; + } + + slot=face->glyph; + + strlength=strlen(string); + if(lengthmetrics.horiBearingYmetrics.height) + descent=MAX((slot->metrics.height-slot->metrics.horiBearingY)>>6,descent); + else + ascent=MAX(slot->bitmap.rows,ascent); + } + _Unlock(); + + FT_Done_Face(face); + + returnval=ascent+descent; + _Unlock(); + return returnval; +} + +void ScreenDriver::DrawString(const char *string, int32 length, BPoint pt, LayerData *d, escapement_delta *edelta=NULL) +{ + if(!string || !d || !d->font) + return; + + _Lock(); + + pt.y--; // because of Be's backward compatibility hack + + ServerFont *font=d->font; + FontStyle *style=font->Style(); + + if(!style) + { + _Unlock(); + return; + } + + FT_Face face; + FT_GlyphSlot slot; + FT_Matrix rmatrix,smatrix; + FT_UInt glyph_index, previous=0; + FT_Vector pen,delta,space,nonspace; + int16 error=0; + int32 strlength,i; + Angle rotation(font->Rotation()), shear(font->Shear()); + + bool antialias=( (font->Size()<18 && font->Flags()& B_DISABLE_ANTIALIASING==0) + || font->Flags()& B_FORCE_ANTIALIASING)?true:false; + + // Originally, I thought to do this shear checking here, but it really should be + // done in BFont::SetShear() + float shearangle=shear.Value(); + if(shearangle>135) + shearangle=135; + if(shearangle<45) + shearangle=45; + + if(shearangle>90) + shear=90+((180-shearangle)*2); + else + shear=90-(90-shearangle)*2; + + error=FT_New_Face(ftlib, style->GetPath(), 0, &face); + if(error) + { + printf("Couldn't create face object\n"); + _Unlock(); + return; + } + + slot=face->glyph; + + bool use_kerning=FT_HAS_KERNING(face) && font->Spacing()==B_STRING_SPACING; + + error=FT_Set_Char_Size(face, 0,int32(font->Size())*64,72,72); + if(error) + { + _Unlock(); + return; + } + + // if we do any transformation, we do a call to FT_Set_Transform() here + + // First, rotate + rmatrix.xx = (FT_Fixed)( rotation.Cosine()*0x10000); + rmatrix.xy = (FT_Fixed)( rotation.Sine()*0x10000); + rmatrix.yx = (FT_Fixed)(-rotation.Sine()*0x10000); + rmatrix.yy = (FT_Fixed)( rotation.Cosine()*0x10000); + + // Next, shear + smatrix.xx = (FT_Fixed)(0x10000); + smatrix.xy = (FT_Fixed)(-shear.Cosine()*0x10000); + smatrix.yx = (FT_Fixed)(0); + smatrix.yy = (FT_Fixed)(0x10000); + + //FT_Matrix_Multiply(&rmatrix,&smatrix); + FT_Matrix_Multiply(&smatrix,&rmatrix); + + // Set up the increment value for escapement padding + space.x=int32(d->edelta.space * rotation.Cosine()*64); + space.y=int32(d->edelta.space * rotation.Sine()*64); + nonspace.x=int32(d->edelta.nonspace * rotation.Cosine()*64); + nonspace.y=int32(d->edelta.nonspace * rotation.Sine()*64); + + // set the pen position in 26.6 cartesian space coordinates + pen.x=(int32)pt.x * 64; + pen.y=(int32)pt.y * 64; + + slot=face->glyph; + + + strlength=strlen(string); + if(lengthbitmap, + BPoint(slot->bitmap_left,pt.y-(slot->bitmap_top-pt.y)), d); + else + BlitMono2RGB32(&slot->bitmap, + BPoint(slot->bitmap_left,pt.y-(slot->bitmap_top-pt.y)), d); + } + else + printf("Couldn't load character %c\n", string[i]); + + // increment pen position + pen.x+=slot->advance.x; + pen.y+=slot->advance.y; + previous=glyph_index; + } + FT_Done_Face(face); + _Unlock(); +} + +void ScreenDriver::BlitMono2RGB32(FT_Bitmap *src, BPoint pt, LayerData *d) +{ + rgb_color color=d->highcolor.GetColor32(); + + // pointers to the top left corner of the area to be copied in each bitmap + uint8 *srcbuffer, *destbuffer; + + // index pointers which are incremented during the course of the blit + uint8 *srcindex, *destindex, *rowptr, value; + + // increment values for the index pointers + int32 srcinc=src->pitch, destinc=fbuffer->gcinfo.bytes_per_row; + + int16 i,j,k, srcwidth=src->pitch, srcheight=src->rows; + int32 x=(int32)pt.x,y=(int32)pt.y; + + // starting point in source bitmap + srcbuffer=(uint8*)src->buffer; + + if(y<0) + { + if(yfbuffer->gcinfo.height) + { + if(y>pt.y) + y--; + srcheight-=(y+srcheight-1)-fbuffer->gcinfo.height; + } + + if(x+srcwidth>fbuffer->gcinfo.width) + { + if(x>pt.x) + x--; + srcwidth-=(x+srcwidth-1)-fbuffer->gcinfo.width; + } + + if(x<0) + { + if(x>3; + srcwidth-=0-x; + destbuffer+=(0-x)*4; + } + + // starting point in destination bitmap + destbuffer=(uint8*)fbuffer->gcinfo.frame_buffer+int32( (pt.y*fbuffer->gcinfo.bytes_per_row)+(pt.x*4) ); + + srcindex=srcbuffer; + destindex=destbuffer; + + for(i=0; ihighcolor.GetColor32(), lowcolor=d->lowcolor.GetColor32(); float rstep,gstep,bstep,astep; + + rstep=float(highcolor.red-lowcolor.red)/255.0; + gstep=float(highcolor.green-lowcolor.green)/255.0; + bstep=float(highcolor.blue-lowcolor.blue)/255.0; + astep=float(highcolor.alpha-lowcolor.alpha)/255.0; + + // increment values for the index pointers + int32 x=(int32)pt.x, + y=(int32)pt.y, + srcinc=src->pitch, +// destinc=dest->BytesPerRow(), + destinc=fbuffer->gcinfo.bytes_per_row, + srcwidth=src->width, + srcheight=src->rows, + incval=0; + + int16 i,j; + + // starting point in source bitmap + srcbuffer=(uint8*)src->buffer; + + // starting point in destination bitmap +// destbuffer=(uint8*)dest->Bits()+(y*dest->BytesPerRow()+(x*4)); + destbuffer=(uint8*)fbuffer->gcinfo.frame_buffer+(y*fbuffer->gcinfo.bytes_per_row+(x*4)); + + + if(y<0) + { + if(yfbuffer->gcinfo.height) + { + if(y>pt.y) + y--; + srcheight-=(y+srcheight-1)-fbuffer->gcinfo.height; + } + + if(x+srcwidth>fbuffer->gcinfo.width) + { + if(x>pt.x) + x--; + srcwidth-=(x+srcwidth-1)-fbuffer->gcinfo.width; + } + + if(x<0) + { + if(xdraw_mode==B_OP_COPY) + { + rowptr[0]=uint8(highcolor.blue-(value*bstep)); + rowptr[1]=uint8(highcolor.green-(value*gstep)); + rowptr[2]=uint8(highcolor.red-(value*rstep)); + rowptr[3]=255; + } + else + if(d->draw_mode==B_OP_OVER) + { + if(highcolor.alpha>127) + { + rowptr[0]=uint8(highcolor.blue-(value*(float(highcolor.blue-rowptr[0])/255.0))); + rowptr[1]=uint8(highcolor.green-(value*(float(highcolor.green-rowptr[1])/255.0))); + rowptr[2]=uint8(highcolor.red-(value*(float(highcolor.red-rowptr[2])/255.0))); + rowptr[3]=255; + } + } + } + rowptr+=4; + + } + + srcindex+=srcinc; + destindex+=destinc; + } +} + +rgb_color ScreenDriver::GetBlitColor(rgb_color src, rgb_color dest, LayerData *d, bool use_high=true) +{ + rgb_color returncolor={0,0,0,0}; + int16 value; + if(!d) + return returncolor; + + switch(d->draw_mode) + { + case B_OP_COPY: + { + return src; + } + case B_OP_ADD: + { + value=src.red+dest.red; + returncolor.red=(value>255)?255:value; + + value=src.green+dest.green; + returncolor.green=(value>255)?255:value; + + value=src.blue+dest.blue; + returncolor.blue=(value>255)?255:value; + return returncolor; + } + case B_OP_SUBTRACT: + { + value=src.red-dest.red; + returncolor.red=(value<0)?0:value; + + value=src.green-dest.green; + returncolor.green=(value<0)?0:value; + + value=src.blue-dest.blue; + returncolor.blue=(value<0)?0:value; + return returncolor; + } + case B_OP_BLEND: + { + value=int16(src.red+dest.red)>>1; + returncolor.red=value; + + value=int16(src.green+dest.green)>>1; + returncolor.green=value; + + value=int16(src.blue+dest.blue)>>1; + returncolor.blue=value; + return returncolor; + } + case B_OP_MIN: + { + + return ( uint16(src.red+src.blue+src.green) > + uint16(dest.red+dest.blue+dest.green) )?dest:src; + } + case B_OP_MAX: + { + return ( uint16(src.red+src.blue+src.green) < + uint16(dest.red+dest.blue+dest.green) )?dest:src; + } + case B_OP_OVER: + { + return (use_high && src.alpha>127)?src:dest; + } + case B_OP_INVERT: + { + returncolor.red=dest.red ^ 255; + returncolor.green=dest.green ^ 255; + returncolor.blue=dest.blue ^ 255; + return (use_high && src.alpha>127)?returncolor:dest; + } + // This is a pain in the arse to implement, so I'm saving it for the real + // server + case B_OP_ALPHA: + { + return src; + } + case B_OP_ERASE: + { + // This one's tricky. + return (use_high && src.alpha>127)?d->lowcolor.GetColor32():dest; + } + case B_OP_SELECT: + { + // This one's tricky, too. We are passed a color in src. If it's the layer's + // high color or low color, we check for a swap. + if(d->highcolor==src) + return (use_high && d->highcolor==dest)?d->lowcolor.GetColor32():dest; + + if(d->lowcolor==src) + return (use_high && d->lowcolor==dest)?d->highcolor.GetColor32():dest; + + return dest; + } + default: + { + break; + } + } + _Unlock(); + return returncolor; +} diff --git a/src/servers/app/server/ScreenDriver.h b/src/servers/app/server/ScreenDriver.h new file mode 100644 index 0000000000..03ed251d44 --- /dev/null +++ b/src/servers/app/server/ScreenDriver.h @@ -0,0 +1,158 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: ScreenDriver.h +// Author: DarkWyrm +// Description: BWindowScreen graphics module +// +//------------------------------------------------------------------------------ +#ifndef _SCREENDRIVER_H_ +#define _SCREENDRIVER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include // for clipping_rect definition +#include +#include "DisplayDriver.h" +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +class VDWindow; +class ServerCursor; +class ServerBitmap; +class RGBColor; +class PortLink; + + +class FrameBuffer : public BWindowScreen +{ +public: + FrameBuffer(const char *title, uint32 space, status_t *st,bool debug); + ~FrameBuffer(void); + void ScreenConnected(bool connected); + void MessageReceived(BMessage *msg); + bool IsConnected(void) const { return is_connected; } + bool QuitRequested(void); + + graphics_card_info gcinfo; +protected: + bool is_connected; + PortLink *serverlink; + BPoint mousepos; + uint32 buttons; +}; + +/* + ScreenDriver.cpp + Replacement class for the ViewDriver which utilizes a BWindowScreen for ease + of testing without requiring a second video card for SecondDriver and also + without the limitations (mostly speed) of ViewDriver. + + This module also emulates the input server via the keyboard. + Cursor keys move the mouse and the left modifier keys Option and Ctrl, which + operate the first and second mouse buttons, respectively. + The right window key on American keymaps doesn't map to anything, so it is + not used. Consequently, when a right modifier key is pressed, it works normally. + + The concept is pretty close to the retooled ViewDriver, where each module + call locks a couple BLockers and draws to the buffer. + + Components: + ScreenDriver: actual driver module + FrameBuffer: BWindowScreen derivative which provides the module access + to the video card + Internal functions for doing graphics on the buffer +*/ +class ScreenDriver : public DisplayDriver +{ +public: + ScreenDriver(void); + ~ScreenDriver(void); + + bool Initialize(void); + void Shutdown(void); + + // Settings functions +// virtual void CopyBits(BRect src, BRect dest); + virtual void DrawBitmap(ServerBitmap *bmp, BRect src, BRect dest, LayerData *d); +// virtual void DrawPicture(SPicture *pic, BPoint pt); + virtual void DrawString(const char *string, int32 length, BPoint pt, LayerData *d, escapement_delta *delta=NULL); + +// virtual void FillArc(BRect r, float angle, float span, LayerData *d, int8 *pat); +// virtual void FillBezier(BPoint *pts, LayerData *d, int8 *pat); + virtual void FillEllipse(BRect r, LayerData *d, int8 *pat); +// virtual void FillPolygon(BPoint *ptlist, int32 numpts, BRect rect, LayerData *d, int8 *pat); + virtual void FillRect(BRect r, LayerData *d, int8 *pat); + virtual void FillRoundRect(BRect r, float xrad, float yrad, LayerData *d, int8 *pat); +// virtual void FillShape(SShape *sh, LayerData *d, int8 *pat); + virtual void FillTriangle(BPoint *pts, BRect r, LayerData *d, int8 *pat); + + virtual void HideCursor(void); + virtual void MoveCursorTo(float x, float y); + virtual void InvertRect(BRect r); + virtual void ShowCursor(void); + virtual void ObscureCursor(void); + virtual void SetCursor(ServerCursor *cursor); + + virtual void StrokeArc(BRect r, float angle, float span, LayerData *d, int8 *pat); + virtual void StrokeBezier(BPoint *pts, LayerData *d, int8 *pat); + virtual void StrokeEllipse(BRect r, LayerData *d, int8 *pat); + virtual void StrokeLine(BPoint start, BPoint end, LayerData *d, int8 *pat); + virtual void StrokePolygon(BPoint *ptlist, int32 numpts, BRect rect, LayerData *d, int8 *pat, bool is_closed=true); + virtual void StrokeRect(BRect r, LayerData *d, int8 *pat); + virtual void StrokeRoundRect(BRect r, float xrad, float yrad, LayerData *d, int8 *pat); +// virtual void StrokeShape(SShape *sh, LayerData *d, int8 *pat); + virtual void StrokeTriangle(BPoint *pts, BRect r, LayerData *d, int8 *pat); +// virtual void StrokeLineArray(BPoint *pts, int32 numlines, RGBColor *colors, LayerData *d); + virtual void SetMode(int32 mode); + float StringWidth(const char *string, int32 length, LayerData *d); + float StringHeight(const char *string, int32 length, LayerData *d); +// virtual bool DumpToFile(const char *path); +protected: + void BlitMono2RGB32(FT_Bitmap *src, BPoint pt, LayerData *d); + void BlitGray2RGB32(FT_Bitmap *src, BPoint pt, LayerData *d); + void BlitBitmap(ServerBitmap *sourcebmp, BRect sourcerect, BRect destrect, drawing_mode mode=B_OP_COPY); + void ExtractToBitmap(ServerBitmap *destbmp, BRect destrect, BRect sourcerect); + void SetPixelPattern(int x, int y, uint8 *pattern, uint8 patternindex); + void Line(BPoint start, BPoint end, LayerData *d, int8 *pat); + void HLine(int32 x1, int32 x2, int32 y, RGBColor color); + rgb_color GetBlitColor(rgb_color src, rgb_color dest, LayerData *d, bool use_high=true); + void SetPixel(int x, int y, RGBColor col); + void SetPixel32(int x, int y, rgb_color col); + void SetPixel16(int x, int y, uint16 col); + void SetPixel8(int x, int y, uint8 col); + void SetThickPixel(int x, int y, int thick, RGBColor col); + void SetThickPixel32(int x, int y, int thick, rgb_color col); + void SetThickPixel16(int x, int y, int thick, uint16 col); + void SetThickPixel8(int x, int y, int thick, uint8 col); + FrameBuffer *fbuffer; + ServerCursor *cursor, *under_cursor; + int32 drawmode; + BRect cursorframe; +}; + +#endif diff --git a/src/servers/app/server/ServerConfig.h b/src/servers/app/server/ServerConfig.h index a574cdd2b4..2743574e01 100644 --- a/src/servers/app/server/ServerConfig.h +++ b/src/servers/app/server/ServerConfig.h @@ -23,6 +23,10 @@ // Display driver to be used by the server. #define DISPLAYDRIVER VIEWDRIVER +// Define this if you want the display driver to emulate the input server. +// Comment this out if DISPLAYDRIVER is defined as HWDRIVER. +#define ENABLE_INPUT_SERVER_EMULATION + // Server port names. The input port is the port which is used to receive // input messages from the Input Server. The other is the "main" port for // the server and is utilized mostly by BApplication objects. diff --git a/src/servers/app/server/ViewDriver.cpp b/src/servers/app/server/ViewDriver.cpp new file mode 100644 index 0000000000..bd734df1a3 --- /dev/null +++ b/src/servers/app/server/ViewDriver.cpp @@ -0,0 +1,1422 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: ViewDriver.cpp +// Author: DarkWyrm +// Description: BView/BWindow combination graphics module +// +//------------------------------------------------------------------------------ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Angle.h" +#include "PortLink.h" +#include "ServerProtocol.h" +#include "ServerBitmap.h" +#include "ViewDriver.h" +#include "ServerConfig.h" +#include "ServerCursor.h" +#include "ServerFont.h" +#include "FontFamily.h" +#include "LayerData.h" + +enum +{ +VDWIN_CLEAR=100, + +VDWIN_SHOWCURSOR, +VDWIN_HIDECURSOR, +VDWIN_OBSCURECURSOR, +VDWIN_MOVECURSOR, +VDWIN_SETCURSOR, +}; + +ViewDriver *viewdriver_global; + + +VDView::VDView(BRect bounds) + : BView(bounds,"viewdriver_view",B_FOLLOW_ALL, B_WILL_DRAW) +{ + SetViewColor(B_TRANSPARENT_32_BIT); + viewbmp=new BBitmap(bounds,B_RGB32,true); + + // This link for sending mouse messages to the OBAppServer. + // This is only to take the place of the Input Server. I suppose I could write + // an addon filter to be more like the Input Server, but then I wouldn't be working + // on this thing! :P + serverlink=new PortLink(find_port(SERVER_INPUT_PORT)); + + // Create a cursor which isn't just a box + cursor=new BBitmap(BRect(0,0,20,20),B_RGBA32,true); + BView *v=new BView(cursor->Bounds(),"v", B_FOLLOW_NONE, B_WILL_DRAW); + hide_cursor=0; + + cursor->Lock(); + cursor->AddChild(v); + + v->SetHighColor(255,255,255,0); + v->FillRect(cursor->Bounds()); + v->SetHighColor(255,0,0,255); + v->FillTriangle(cursor->Bounds().LeftTop(),cursor->Bounds().RightTop(),cursor->Bounds().LeftBottom()); + + cursor->RemoveChild(v); + cursor->Unlock(); + + cursorframe=cursor->Bounds(); + oldcursorframe=cursor->Bounds(); +} + +VDView::~VDView(void) +{ + delete serverlink; + delete viewbmp; + delete cursor; +} + +void VDView::AttachedToWindow(void) +{ +} + +void VDView::Draw(BRect rect) +{ + if(viewbmp) + { + DrawBitmapAsync(viewbmp,oldcursorframe,oldcursorframe); + DrawBitmapAsync(viewbmp,rect,rect); + + if(hide_cursor==0 && obscure_cursor==false) + { + SetDrawingMode(B_OP_ALPHA); + DrawBitmapAsync(cursor,cursor->Bounds(),cursorframe); + SetDrawingMode(B_OP_COPY); + } + Sync(); + } +} + +// These functions emulate the Input Server by sending the *exact* same kind of messages +// to the server's port. Being we're using a regular window, it would make little sense +// to do anything else. + +void VDView::MouseDown(BPoint pt) +{ + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + // 5) int32 - buttons down + // 6) int32 - clicks +#ifdef ENABLE_INPUT_SERVER_EMULATION + BPoint p; + + uint32 buttons, + mod=modifiers(), + clicks=1; // can't get the # of clicks without a *lot* of extra work :( + + int64 time=(int64)real_time_clock(); + + GetMouse(&p,&buttons); + + serverlink->SetOpCode(B_MOUSE_DOWN); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + serverlink->Attach(&mod, sizeof(uint32)); + serverlink->Attach(&buttons, sizeof(uint32)); + serverlink->Attach(&clicks, sizeof(uint32)); + serverlink->Flush(); +#endif +} + +void VDView::MouseMoved(BPoint pt, uint32 transit, const BMessage *msg) +{ + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down +#ifdef ENABLE_INPUT_SERVER_EMULATION + BPoint p; + uint32 buttons; + int64 time=(int64)real_time_clock(); + + serverlink->SetOpCode(B_MOUSE_MOVED); + serverlink->Attach(&time,sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + GetMouse(&p,&buttons); + serverlink->Attach(&buttons,sizeof(int32)); + serverlink->Flush(); +#endif +} + +void VDView::MouseUp(BPoint pt) +{ + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down +#ifdef ENABLE_INPUT_SERVER_EMULATION + BPoint p; + + uint32 buttons, + mod=modifiers(); + + int64 time=(int64)real_time_clock(); + + GetMouse(&p,&buttons); + + serverlink->SetOpCode(B_MOUSE_UP); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + serverlink->Attach(&mod, sizeof(uint32)); + serverlink->Flush(); +#endif +} + +VDWindow::VDWindow(void) + : BWindow(BRect(100,60,740,540),"OBOS App Server, P7",B_TITLED_WINDOW, + B_NOT_ZOOMABLE | B_NOT_RESIZABLE) +{ + view=new VDView(Bounds()); + AddChild(view); +} + +VDWindow::~VDWindow(void) +{ +} + +void VDWindow::MessageReceived(BMessage *msg) +{ + switch(msg->what) + { + case VDWIN_SHOWCURSOR: + { + if(view->hide_cursor>0) + view->hide_cursor--; + + if(view->hide_cursor==0) + view->Invalidate(view->cursorframe); + + break; + } + case VDWIN_HIDECURSOR: + { + view->hide_cursor++; + if(view->hide_cursor==1) + view->Invalidate(view->cursorframe); + break; + } + case VDWIN_OBSCURECURSOR: + { + view->obscure_cursor=true; + view->Invalidate(view->cursorframe); + break; + } + case VDWIN_MOVECURSOR: + { + float x,y; + msg->FindFloat("x",&x); + msg->FindFloat("y",&y); + + // this was changed because an extra message was + // sent even though the mouse was never moved + if(view->cursorframe.left!=x || view->cursorframe.top!=y) + { + if(view->obscure_cursor) + view->obscure_cursor=false; + + view->oldcursorframe=view->cursorframe; + view->cursorframe.OffsetTo(x,y); + } + + if(view->hide_cursor==0) + view->Invalidate(view->oldcursorframe); + break; + } + case VDWIN_SETCURSOR: + { + ServerBitmap *cdata; + msg->FindPointer("SCursor",(void**)&cdata); + + if(cdata!=NULL) + { + BBitmap *bmp=new BBitmap(cdata->Bounds(), B_RGBA32); + + // Copy the server bitmap in the cursor to a BBitmap + uint8 *sbmppos=(uint8*)cdata->Bits(), + *bbmppos=(uint8*)bmp->Bits(); + + int32 bytes=cdata->BytesPerRow(), + bbytes=bmp->BytesPerRow(); + + for(int i=0;iBounds().IntegerHeight();i++) + memcpy(bbmppos+(i*bbytes), sbmppos+(i*bytes), bytes); + + // Replace the bitmap + delete view->cursor; + view->cursor=bmp; + view->Invalidate(view->cursorframe); + break; + } + break; + } + default: + BWindow::MessageReceived(msg); + break; + } +} + +bool VDWindow::QuitRequested(void) +{ + port_id serverport=find_port(SERVER_PORT_NAME); + + if(serverport!=B_NAME_NOT_FOUND) + write_port(serverport,B_QUIT_REQUESTED,NULL,0); + + return true; +} + +void VDWindow::WindowActivated(bool active) +{ + // This is just to hide the regular system cursor so we can see our own + if(active) + be_app->HideCursor(); + else + be_app->ShowCursor(); +} + +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- + +ViewDriver::ViewDriver(void) +{ + viewdriver_global=this; + screenwin=new VDWindow(); + framebuffer=screenwin->view->viewbmp; + serverlink=screenwin->view->serverlink; + hide_cursor=0; +} + +ViewDriver::~ViewDriver(void) +{ + if(is_initialized) + { + screenwin->Lock(); + screenwin->Quit(); + screenwin=NULL; + } +} + +bool ViewDriver::Initialize(void) +{ + _Lock(); + drawview=new BView(framebuffer->Bounds(),"drawview",B_FOLLOW_ALL, B_WILL_DRAW); + framebuffer->AddChild(drawview); + + hide_cursor=0; + obscure_cursor=false; + + is_initialized=true; + + // We can afford to call the above functions without locking + // because the window is locked until Show() is first called + screenwin->Show(); + _Unlock(); + return true; +} + +void ViewDriver::Shutdown(void) +{ + _Lock(); + is_initialized=false; + _Unlock(); +} + +void ViewDriver::SetMode(int32 space) +{ + screenwin->Lock(); + int16 w=640,h=480; + color_space s; + + switch(space) + { + case B_32_BIT_800x600: + case B_16_BIT_800x600: + case B_8_BIT_800x600: + { + w=800; h=600; + break; + } + case B_32_BIT_1024x768: + case B_16_BIT_1024x768: + case B_8_BIT_1024x768: + { + w=1024; h=768; + break; + } + default: + break; + } + screenwin->ResizeTo(w-1,h-1); + + switch(space) + { + case B_32_BIT_640x480: + case B_32_BIT_800x600: + case B_32_BIT_1024x768: + s=B_RGBA32; + break; + case B_16_BIT_640x480: + case B_16_BIT_800x600: + case B_16_BIT_1024x768: + s=B_RGBA15; + break; + case B_8_BIT_640x480: + case B_8_BIT_800x600: + case B_8_BIT_1024x768: + s=B_CMAP8; + break; + default: + break; + } + + + delete framebuffer; + + screenwin->view->viewbmp=new BBitmap(BRect(0,0,w-1,h-1),s,true); + framebuffer=screenwin->view->viewbmp; + drawview=new BView(framebuffer->Bounds(),"drawview",B_FOLLOW_ALL, B_WILL_DRAW); + framebuffer->AddChild(drawview); + + framebuffer->Lock(); + drawview->SetHighColor(80,85,152); + drawview->FillRect(drawview->Bounds()); + drawview->Sync(); + framebuffer->Unlock(); + screenwin->view->Invalidate(); + screenwin->Unlock(); +} + +void ViewDriver::CopyBits(BRect src, BRect dest) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->CopyBits(src,dest); + drawview->Sync(); + screenwin->view->Invalidate(src); + screenwin->view->Invalidate(dest); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::DrawBitmap(ServerBitmap *bitmap, BRect src, BRect dest) +{ +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: DrawBitmap unimplemented()\n"); +#endif +} + +void ViewDriver::DrawChar(char c, BPoint pt, LayerData *d) +{ + char str[2]; + str[0]=c; + str[1]='\0'; + DrawString(str, 1, pt, d); +} +/* +void ViewDriver::DrawString(const char *string, int32 length, BPoint pt, LayerData *d, escapement_delta *delta=NULL) +{ +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: DrawString(\"%s\",%ld,BPoint(%f,%f))\n",string,length,pt.x,pt.y); +#endif + if(!d) + return; + BRect r; + + screenwin->Lock(); + framebuffer->Lock(); + + SetLayerData(d,true); // set all layer data and additionally set the font-related data + + drawview->DrawString(string,length,pt,delta); + drawview->Sync(); + + // calculate the invalid rectangle + font_height fh; + BFont font; + drawview->GetFont(&font); + drawview->GetFontHeight(&fh); + r.left=pt.x; + r.right=pt.x+font.StringWidth(string); + r.top=pt.y-fh.ascent; + r.bottom=pt.y+fh.descent; + screenwin->view->Invalidate(r); + + framebuffer->Unlock(); + screenwin->Unlock(); + +} +*/ +/* +bool ViewDriver::DumpToFile(const char *path) +{ + return false; +} +*/ +void ViewDriver::FillArc(BRect r, float angle, float span, LayerData *d, int8 *pat) +{ + if(!pat || !d) + return; + screenwin->Lock(); + framebuffer->Lock(); + SetLayerData(d); + drawview->FillArc(r,angle,span,*((pattern*)pat)); + drawview->Sync(); + screenwin->view->Invalidate(r); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillBezier(BPoint *pts, LayerData *d, int8 *pat) +{ + if(!pat || !pts) + return; + screenwin->Lock(); + framebuffer->Lock(); + SetLayerData(d); + drawview->FillBezier(pts,*((pattern*)pat)); + drawview->Sync(); + + // Invalidate the whole view until I get around to adding in the invalid rect calc code + screenwin->view->Invalidate(); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillEllipse(BRect r, LayerData *d, int8 *pat) +{ + if(!pat || !d) + return; + screenwin->Lock(); + framebuffer->Lock(); + SetLayerData(d); + drawview->FillEllipse(r,*((pattern*)pat)); + drawview->Sync(); + screenwin->view->Invalidate(r); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillPolygon(BPoint *ptlist, int32 numpts, BRect rect, LayerData *d, int8 *pat) +{ +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: FillPolygon unimplemented\n"); +#endif + if(!pat || !ptlist) + return; +} + +void ViewDriver::FillRect(BRect r, LayerData *d, int8 *pat) +{ + if(!pat || !d) + return; + screenwin->Lock(); + framebuffer->Lock(); + SetLayerData(d); + drawview->FillRect(r,*((pattern*)pat)); + drawview->Sync(); + screenwin->view->Invalidate(r); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillRoundRect(BRect r, float xrad, float yrad, LayerData *d, int8 *pat) +{ + if(!pat || !d) + return; + screenwin->Lock(); + framebuffer->Lock(); + SetLayerData(d); + drawview->FillRoundRect(r,xrad,yrad,*((pattern*)pat)); + drawview->Sync(); + screenwin->view->Invalidate(r); + framebuffer->Unlock(); + screenwin->Unlock(); + +} + +void ViewDriver::FillTriangle(BPoint *pts, BRect r, LayerData *d, int8 *pat) +{ + if(!pat || !pts) + return; + screenwin->Lock(); + framebuffer->Lock(); + BPoint first=pts[0],second=pts[1],third=pts[2]; + SetLayerData(d); + drawview->FillTriangle(first,second,third,r,*((pattern*)pat)); + drawview->Sync(); + screenwin->view->Invalidate(r); + framebuffer->Unlock(); + screenwin->Unlock(); + +} + +void ViewDriver::HideCursor(void) +{ + screenwin->Lock(); + _Lock(); + + hide_cursor++; + screenwin->PostMessage(VDWIN_HIDECURSOR); + + _Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::InvertRect(BRect r) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->InvertRect(r); + drawview->Sync(); + screenwin->view->Invalidate(r); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +bool ViewDriver::IsCursorHidden(void) +{ + screenwin->Lock(); + bool value=(hide_cursor>0)?true:false; + screenwin->Unlock(); + return value; +} + +void ViewDriver::ObscureCursor(void) +{ + screenwin->Lock(); + screenwin->PostMessage(VDWIN_OBSCURECURSOR); + screenwin->Unlock(); +} + +void ViewDriver::MoveCursorTo(float x, float y) +{ + screenwin->Lock(); + BMessage *msg=new BMessage(VDWIN_MOVECURSOR); + msg->AddFloat("x",x); + msg->AddFloat("y",y); + screenwin->PostMessage(msg); + screenwin->Unlock(); +} + +void ViewDriver::SetCursor(ServerCursor *cursor) +{ + if(cursor!=NULL) + { + screenwin->Lock(); + BBitmap *bmp=new BBitmap(cursor->Bounds(),B_RGBA32); + + // Copy the server bitmap in the cursor to a BBitmap + uint8 *sbmppos=(uint8*)cursor->Bits(), + *bbmppos=(uint8*)bmp->Bits(); + + int32 bytes=cursor->BytesPerRow(), + bbytes=bmp->BytesPerRow(); + + for(int i=0;i<=cursor->Bounds().IntegerHeight();i++) + memcpy(bbmppos+(i*bbytes), sbmppos+(i*bytes), bytes); + + // Replace the bitmap + delete screenwin->view->cursor; + screenwin->view->cursor=bmp; + screenwin->view->Invalidate(screenwin->view->cursorframe); + screenwin->Unlock(); + } +} + +void ViewDriver::ShowCursor(void) +{ + screenwin->Lock(); + if(hide_cursor>0) + { + hide_cursor--; + screenwin->PostMessage(VDWIN_SHOWCURSOR); + } + screenwin->Unlock(); + +} + +void ViewDriver::StrokeArc(BRect r, float angle, float span, LayerData *d, int8 *pat) +{ + if(!pat || !d) + return; + screenwin->Lock(); + framebuffer->Lock(); + SetLayerData(d); + drawview->StrokeArc(r,angle,span,*((pattern*)pat)); + drawview->Sync(); + screenwin->view->Invalidate(r); + framebuffer->Unlock(); + screenwin->Unlock(); + +} + +void ViewDriver::StrokeBezier(BPoint *pts, LayerData *d, int8 *pat) +{ + if(!pat || !pts) + return; + screenwin->Lock(); + framebuffer->Lock(); + SetLayerData(d); + drawview->StrokeBezier(pts,*((pattern*)pat)); + drawview->Sync(); + + // Invalidate the whole view until I get around to adding in the invalid rect calc code + screenwin->view->Invalidate(); + framebuffer->Unlock(); + screenwin->Unlock(); + +} + +void ViewDriver::StrokeEllipse(BRect r, LayerData *d, int8 *pat) +{ + if(!pat || !d) + return; + screenwin->Lock(); + framebuffer->Lock(); + SetLayerData(d); + drawview->StrokeEllipse(r,*((pattern*)pat)); + drawview->Sync(); + screenwin->view->Invalidate(r); + framebuffer->Unlock(); + screenwin->Unlock(); + +} + +void ViewDriver::StrokeLine(BPoint start, BPoint end, LayerData *d, int8 *pat) +{ + if(!pat || !d) + return; + screenwin->Lock(); + framebuffer->Lock(); + SetLayerData(d); + drawview->StrokeLine(start,end,*((pattern*)pat)); + drawview->Sync(); + screenwin->view->Invalidate(BRect(start,end)); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeLineArray(BPoint *pts, int32 numlines, RGBColor *colors, LayerData *d) +{ +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: StrokeLineArray unimplemented\n"); +#endif +} + +void ViewDriver::StrokePolygon(BPoint *ptlist, int32 numpts, BRect rect, LayerData *d, int8 *pat, bool is_closed=true) +{ + if(!pat || !ptlist) + return; + screenwin->Lock(); + framebuffer->Lock(); + + BRegion invalid; + + SetLayerData(d); + drawview->BeginLineArray(numpts+2); + for(int i=1;iAddLine(ptlist[i-1],ptlist[i],d->highcolor.GetColor32()); + invalid.Include(BRect(ptlist[i-1],ptlist[i])); + } + + if(is_closed) + { + drawview->AddLine(ptlist[numpts-1],ptlist[0],d->highcolor.GetColor32()); + invalid.Include(BRect(ptlist[numpts-1],ptlist[0])); + } + drawview->EndLineArray(); + + drawview->Sync(); + screenwin->view->Invalidate(invalid.Frame()); + framebuffer->Unlock(); + screenwin->Unlock(); + +} + +void ViewDriver::StrokeRect(BRect r, LayerData *d, int8 *pat) +{ + if(!pat || !d) + return; + screenwin->Lock(); + framebuffer->Lock(); + SetLayerData(d); + drawview->StrokeRect(r,*((pattern*)pat)); + drawview->Sync(); + screenwin->view->Invalidate(r); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeRoundRect(BRect r, float xrad, float yrad, LayerData *d, int8 *pat) +{ + if(!pat || !d) + return; + screenwin->Lock(); + framebuffer->Lock(); + SetLayerData(d); + drawview->StrokeRoundRect(r,xrad,yrad,*((pattern*)pat)); + drawview->Sync(); + screenwin->view->Invalidate(r); + framebuffer->Unlock(); + screenwin->Unlock(); + +} + +void ViewDriver::StrokeTriangle(BPoint *pts, BRect r, LayerData *d, int8 *pat) +{ + if(!pat || !pts || !d) + return; + screenwin->Lock(); + framebuffer->Lock(); + BPoint first=pts[0],second=pts[1],third=pts[2]; + SetLayerData(d); + drawview->StrokeTriangle(first,second,third,r,*((pattern*)pat)); + drawview->Sync(); + screenwin->view->Invalidate(r); + framebuffer->Unlock(); + screenwin->Unlock(); + +} + +void ViewDriver::SetLayerData(LayerData *d, bool set_font_data=false) +{ + if(!d) + return; + + drawview->SetPenSize(d->pensize); + drawview->SetDrawingMode(d->draw_mode); + drawview->SetHighColor(d->highcolor.GetColor32()); + drawview->SetLowColor(d->lowcolor.GetColor32()); + drawview->SetScale(d->scale); + drawview->MovePenTo(d->penlocation); + if(set_font_data) + { + BFont font; + ServerFont *sf=d->font; + + if(!sf) + return; + + FontStyle *style=d->font->Style(); + + if(!style) + return; + + FontFamily *family=(FontFamily *)style->Family(); + if(!family) + return; + + font.SetFamilyAndStyle((font_family)family->Name(),style->Name()); + font.SetFlags(sf->Flags()); + font.SetEncoding(sf->Encoding()); + font.SetSize(sf->Size()); + font.SetRotation(sf->Rotation()); + font.SetShear(sf->Shear()); + font.SetSpacing(sf->Spacing()); + drawview->SetFont(&font); + } +} + +float ViewDriver::StringWidth(const char *string, int32 length, LayerData *d) +{ + if(!string || !d || !d->font) + return 0.0; + screenwin->Lock(); + + ServerFont *font=d->font; + FontStyle *style=font->Style(); + + if(!style) + return 0.0; + + FT_Face face; + FT_GlyphSlot slot; + FT_UInt glyph_index, previous=0; + FT_Vector pen,delta; + int16 error=0; + int32 strlength,i; + float returnval; + + error=FT_New_Face(ftlib, style->GetPath(), 0, &face); + if(error) + return 0.0; + + slot=face->glyph; + + bool use_kerning=FT_HAS_KERNING(face) && font->Spacing()==B_STRING_SPACING; + + error=FT_Set_Char_Size(face, 0,int32(font->Size())*64,72,72); + if(error) + return 0.0; + + // set the pen position in 26.6 cartesian space coordinates + pen.x=0; + + slot=face->glyph; + + strlength=strlen(string); + if(lengthadvance.x; + previous=glyph_index; + } + screenwin->Unlock(); + + FT_Done_Face(face); + + returnval=pen.x>>6; + return returnval; +} + +float ViewDriver::StringHeight(const char *string, int32 length, LayerData *d) +{ + if(!string || !d || !d->font) + return 0.0; + screenwin->Lock(); + + ServerFont *font=d->font; + FontStyle *style=font->Style(); + + if(!style) + return 0.0; + + FT_Face face; + FT_GlyphSlot slot; + int16 error=0; + int32 strlength,i; + float returnval=0.0,ascent=0.0,descent=0.0; + + error=FT_New_Face(ftlib, style->GetPath(), 0, &face); + if(error) + return 0.0; + + slot=face->glyph; + + error=FT_Set_Char_Size(face, 0,int32(font->Size())*64,72,72); + if(error) + return 0.0; + + slot=face->glyph; + + strlength=strlen(string); + if(lengthmetrics.horiBearingYmetrics.height) + descent=MAX((slot->metrics.height-slot->metrics.horiBearingY)>>6,descent); + else + ascent=MAX(slot->bitmap.rows,ascent); + } + screenwin->Unlock(); + + FT_Done_Face(face); + + returnval=ascent+descent; + return returnval; +} + +void ViewDriver::DrawString(const char *string, int32 length, BPoint pt, LayerData *d, escapement_delta *edelta=NULL) +{ + if(!string || !d || !d->font) + return; + screenwin->Lock(); + + pt.y--; // because of Be's backward compatibility hack + + ServerFont *font=d->font; + FontStyle *style=font->Style(); + + if(!style) + return; + + FT_Face face; + FT_GlyphSlot slot; + FT_Matrix rmatrix,smatrix; + FT_UInt glyph_index, previous=0; + FT_Vector pen,delta,space,nonspace; + int16 error=0; + int32 strlength,i; + Angle rotation(font->Rotation()), shear(font->Shear()); + + bool antialias=( (font->Size()<18 && font->Flags()& B_DISABLE_ANTIALIASING==0) + || font->Flags()& B_FORCE_ANTIALIASING)?true:false; + + // Originally, I thought to do this shear checking here, but it really should be + // done in BFont::SetShear() + float shearangle=shear.Value(); + if(shearangle>135) + shearangle=135; + if(shearangle<45) + shearangle=45; + + if(shearangle>90) + shear=90+((180-shearangle)*2); + else + shear=90-(90-shearangle)*2; + + error=FT_New_Face(ftlib, style->GetPath(), 0, &face); + if(error) + return; + + slot=face->glyph; + + bool use_kerning=FT_HAS_KERNING(face) && font->Spacing()==B_STRING_SPACING; + + error=FT_Set_Char_Size(face, 0,int32(font->Size())*64,72,72); + if(error) + return; + + // if we do any transformation, we do a call to FT_Set_Transform() here + + // First, rotate + rmatrix.xx = (FT_Fixed)( rotation.Cosine()*0x10000); + rmatrix.xy = (FT_Fixed)(-rotation.Sine()*0x10000); + rmatrix.yx = (FT_Fixed)( rotation.Sine()*0x10000); + rmatrix.yy = (FT_Fixed)( rotation.Cosine()*0x10000); + + // Next, shear + smatrix.xx = (FT_Fixed)(0x10000); + smatrix.xy = (FT_Fixed)(-shear.Cosine()*0x10000); + smatrix.yx = (FT_Fixed)(0); + smatrix.yy = (FT_Fixed)(0x10000); + + FT_Matrix_Multiply(&rmatrix,&smatrix); + + // Set up the increment value for escapement padding + space.x=int32(d->edelta.space * rotation.Cosine()*64); + space.y=int32(d->edelta.space * rotation.Sine()*64); + nonspace.x=int32(d->edelta.nonspace * rotation.Cosine()*64); + nonspace.y=int32(d->edelta.nonspace * rotation.Sine()*64); + + // set the pen position in 26.6 cartesian space coordinates + pen.x=(int32)pt.x * 64; + pen.y=(int32)pt.y * 64; + + slot=face->glyph; + + + strlength=strlen(string); + if(lengthbitmap, + BPoint(slot->bitmap_left,pt.y-(slot->bitmap_top-pt.y)), d); + else + BlitMono2RGB32(&slot->bitmap, + BPoint(slot->bitmap_left,pt.y-(slot->bitmap_top-pt.y)), d); + } + + // increment pen position + pen.x+=slot->advance.x; + pen.y+=slot->advance.y; + previous=glyph_index; + } + + // TODO: implement properly + // calculate the invalid rectangle + BRect r; + r.left=MIN(pt.x,pen.x>>6); + r.right=MAX(pt.x,pen.x>>6); + r.top=pt.y-face->height; + r.bottom=pt.y+face->height; + + screenwin->view->Invalidate(r); + screenwin->Unlock(); + + FT_Done_Face(face); +} + +void ViewDriver::BlitMono2RGB32(FT_Bitmap *src, BPoint pt, LayerData *d) +{ + rgb_color color=d->highcolor.GetColor32(); + + // pointers to the top left corner of the area to be copied in each bitmap + uint8 *srcbuffer, *destbuffer; + + // index pointers which are incremented during the course of the blit + uint8 *srcindex, *destindex, *rowptr, value; + + // increment values for the index pointers + int32 srcinc=src->pitch, destinc=framebuffer->BytesPerRow(); + + int16 i,j,k, srcwidth=src->pitch, srcheight=src->rows; + int32 x=(int32)pt.x,y=(int32)pt.y; + + // starting point in source bitmap + srcbuffer=(uint8*)src->buffer; + + if(y<0) + { + if(yframebuffer->Bounds().IntegerHeight()) + { + if(y>pt.y) + y--; + srcheight-=(y+srcheight-1)-framebuffer->Bounds().IntegerHeight(); + } + + if(x+srcwidth>framebuffer->Bounds().IntegerWidth()) + { + if(x>pt.x) + x--; + srcwidth-=(x+srcwidth-1)-framebuffer->Bounds().IntegerWidth(); + } + + if(x<0) + { + if(x>3; + srcwidth-=0-x; + destbuffer+=(0-x)*4; + } + + // starting point in destination bitmap + destbuffer=(uint8*)framebuffer->Bits()+int32( (pt.y*framebuffer->BytesPerRow())+(pt.x*4) ); + + srcindex=srcbuffer; + destindex=destbuffer; + + for(i=0; ihighcolor.GetColor32(), lowcolor=d->lowcolor.GetColor32(); float rstep,gstep,bstep,astep; + + rstep=float(highcolor.red-lowcolor.red)/255.0; + gstep=float(highcolor.green-lowcolor.green)/255.0; + bstep=float(highcolor.blue-lowcolor.blue)/255.0; + astep=float(highcolor.alpha-lowcolor.alpha)/255.0; + + // increment values for the index pointers + int32 x=(int32)pt.x, + y=(int32)pt.y, + srcinc=src->pitch, +// destinc=dest->BytesPerRow(), + destinc=framebuffer->BytesPerRow(), + srcwidth=src->width, + srcheight=src->rows, + incval=0; + + int16 i,j; + + // starting point in source bitmap + srcbuffer=(uint8*)src->buffer; + + // starting point in destination bitmap +// destbuffer=(uint8*)dest->Bits()+(y*dest->BytesPerRow()+(x*4)); + destbuffer=(uint8*)framebuffer->Bits()+(y*framebuffer->BytesPerRow()+(x*4)); + + + if(y<0) + { + if(yframebuffer->Bounds().IntegerHeight()) + { + if(y>pt.y) + y--; + srcheight-=(y+srcheight-1)-framebuffer->Bounds().IntegerHeight(); + } + + if(x+srcwidth>framebuffer->Bounds().IntegerWidth()) + { + if(x>pt.x) + x--; + srcwidth-=(x+srcwidth-1)-framebuffer->Bounds().IntegerWidth(); + } + + if(x<0) + { + if(xdraw_mode==B_OP_COPY) + { + rowptr[0]=uint8(highcolor.blue-(value*bstep)); + rowptr[1]=uint8(highcolor.green-(value*gstep)); + rowptr[2]=uint8(highcolor.red-(value*rstep)); + rowptr[3]=255; + } + else + if(d->draw_mode==B_OP_OVER) + { + if(highcolor.alpha>127) + { + rowptr[0]=uint8(highcolor.blue-(value*(float(highcolor.blue-rowptr[0])/255.0))); + rowptr[1]=uint8(highcolor.green-(value*(float(highcolor.green-rowptr[1])/255.0))); + rowptr[2]=uint8(highcolor.red-(value*(float(highcolor.red-rowptr[2])/255.0))); + rowptr[3]=255; + } + } + } + rowptr+=4; + + } + + srcindex+=srcinc; + destindex+=destinc; + } +} + +rgb_color ViewDriver::GetBlitColor(rgb_color src, rgb_color dest, LayerData *d, bool use_high=true) +{ + rgb_color returncolor={0,0,0,0}; + int16 value; + if(!d) + return returncolor; + + switch(d->draw_mode) + { + case B_OP_COPY: + { + return src; + } + case B_OP_ADD: + { + value=src.red+dest.red; + returncolor.red=(value>255)?255:value; + + value=src.green+dest.green; + returncolor.green=(value>255)?255:value; + + value=src.blue+dest.blue; + returncolor.blue=(value>255)?255:value; + return returncolor; + } + case B_OP_SUBTRACT: + { + value=src.red-dest.red; + returncolor.red=(value<0)?0:value; + + value=src.green-dest.green; + returncolor.green=(value<0)?0:value; + + value=src.blue-dest.blue; + returncolor.blue=(value<0)?0:value; + return returncolor; + } + case B_OP_BLEND: + { + value=int16(src.red+dest.red)>>1; + returncolor.red=value; + + value=int16(src.green+dest.green)>>1; + returncolor.green=value; + + value=int16(src.blue+dest.blue)>>1; + returncolor.blue=value; + return returncolor; + } + case B_OP_MIN: + { + + return ( uint16(src.red+src.blue+src.green) > + uint16(dest.red+dest.blue+dest.green) )?dest:src; + } + case B_OP_MAX: + { + return ( uint16(src.red+src.blue+src.green) < + uint16(dest.red+dest.blue+dest.green) )?dest:src; + } + case B_OP_OVER: + { + return (use_high && src.alpha>127)?src:dest; + } + case B_OP_INVERT: + { + returncolor.red=dest.red ^ 255; + returncolor.green=dest.green ^ 255; + returncolor.blue=dest.blue ^ 255; + return (use_high && src.alpha>127)?returncolor:dest; + } + // This is a pain in the arse to implement, so I'm saving it for the real + // server + case B_OP_ALPHA: + { + return src; + } + case B_OP_ERASE: + { + // This one's tricky. + return (use_high && src.alpha>127)?d->lowcolor.GetColor32():dest; + } + case B_OP_SELECT: + { + // This one's tricky, too. We are passed a color in src. If it's the layer's + // high color or low color, we check for a swap. + if(d->highcolor==src) + return (use_high && d->highcolor==dest)?d->lowcolor.GetColor32():dest; + + if(d->lowcolor==src) + return (use_high && d->lowcolor==dest)?d->highcolor.GetColor32():dest; + + return dest; + } + default: + { + break; + } + } + return returncolor; +} diff --git a/src/servers/app/server/ViewDriver.h b/src/servers/app/server/ViewDriver.h new file mode 100644 index 0000000000..d22609e769 --- /dev/null +++ b/src/servers/app/server/ViewDriver.h @@ -0,0 +1,170 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: ViewDriver.h +// Author: DarkWyrm +// Description: BView/BWindow combination graphics module +// +//------------------------------------------------------------------------------ +#ifndef _VIEWDRIVER_H_ +#define _VIEWDRIVER_H_ + +#include +#include +#include +#include +#include // for pattern struct +#include +#include +#include +#include +#include "DisplayDriver.h" +#include +#include FT_FREETYPE_H + +class BBitmap; +class PortLink; +class VDWindow; +class LayerData; + +class VDView : public BView +{ +public: + VDView(BRect bounds); + ~VDView(void); + void AttachedToWindow(void); + void Draw(BRect rect); + void MouseDown(BPoint pt); + void MouseMoved(BPoint pt, uint32 transit, const BMessage *msg); + void MouseUp(BPoint pt); + + BBitmap *viewbmp; + PortLink *serverlink; + + int hide_cursor; + BBitmap *cursor; + + BRect cursorframe, oldcursorframe; + bool obscure_cursor; +}; + +class VDWindow : public BWindow +{ +public: + VDWindow(void); + ~VDWindow(void); + void MessageReceived(BMessage *msg); + bool QuitRequested(void); + void WindowActivated(bool active); + + VDView *view; +}; + +/*! + \brief BView/BWindow combination graphics module + + First, slowest, and easiest driver class in the app_server which is designed + to utilize the BeOS graphics functions to cut out a lot of junk in getting the + drawing infrastructure in this server. + + The concept is to have VDView::Draw() draw a bitmap, which is a "frame buffer" + of sorts, utilize a second view to write to it. This cuts out + the most problems with having a crapload of code to get just right without + having to write a bunch of unit tests + + Components: 3 classes, VDView, VDWindow, and ViewDriver + + ViewDriver - a wrapper class which mostly posts messages to the VDWindow + VDWindow - does most of the work. + VDView - doesn't do all that much except display the rendered bitmap +*/ +class ViewDriver : public DisplayDriver +{ +public: + ViewDriver(void); + ~ViewDriver(void); + + bool Initialize(void); // Sets the driver + void Shutdown(void); // You never know when you'll need this + + // Drawing functions + void CopyBits(BRect src, BRect dest); + void DrawBitmap(ServerBitmap *bmp, BRect src, BRect dest); + void DrawChar(char c, BPoint pt, LayerData *d); +// virtual void DrawPicture(SPicture *pic, BPoint pt); + void DrawString(const char *string, int32 length, BPoint pt, LayerData *d, escapement_delta *delta=NULL); + + void FillArc(BRect r, float angle, float span, LayerData *d, int8 *pat); + void FillBezier(BPoint *pts, LayerData *d, int8 *pat); + void FillEllipse(BRect r, LayerData *d, int8 *pat); + void FillPolygon(BPoint *ptlist, int32 numpts, BRect rect, LayerData *d, int8 *pat); + void FillRect(BRect r, LayerData *d, int8 *pat); + void FillRoundRect(BRect r, float xrad, float yrad, LayerData *d, int8 *pat); +// void FillShape(SShape *sh, LayerData *d, int8 *pat); + void FillTriangle(BPoint *pts, BRect r, LayerData *d, int8 *pat); + + void HideCursor(void); + void InvertRect(BRect r); + bool IsCursorHidden(void); + void MoveCursorTo(float x, float y); +// void MovePenTo(BPoint pt); + void ObscureCursor(void); +// BPoint PenPosition(void); +// float PenSize(void); + void SetCursor(ServerCursor *cursor); +// drawing_mode GetDrawingMode(void); +// void SetDrawingMode(drawing_mode mode); + void ShowCursor(void); + + void StrokeArc(BRect r, float angle, float span, LayerData *d, int8 *pat); + void StrokeBezier(BPoint *pts, LayerData *d, int8 *pat); + void StrokeEllipse(BRect r, LayerData *d, int8 *pat); + void StrokeLine(BPoint start, BPoint end, LayerData *d, int8 *pat); + void StrokeLineArray(BPoint *pts, int32 numlines, RGBColor *colors, LayerData *d); + void StrokePolygon(BPoint *ptlist, int32 numpts, BRect rect, LayerData *d, int8 *pat, bool is_closed=true); + void StrokeRect(BRect r, LayerData *d, int8 *pat); + void StrokeRoundRect(BRect r, float xrad, float yrad, LayerData *d, int8 *pat); +// void StrokeShape(SShape *sh, LayerData *d, int8 *pat); + void StrokeTriangle(BPoint *pts, BRect r, LayerData *d, int8 *pat); + void SetMode(int32 mode); + float StringWidth(const char *string, int32 length, LayerData *d); + float StringHeight(const char *string, int32 length, LayerData *d); +// bool DumpToFile(const char *path); + VDWindow *screenwin; +protected: + void SetLayerData(LayerData *d, bool set_font_data=false); + void BlitMono2RGB32(FT_Bitmap *src, BPoint pt, LayerData *d); + void BlitGray2RGB32(FT_Bitmap *src, BPoint pt, LayerData *d); + rgb_color GetBlitColor(rgb_color src, rgb_color dest, LayerData *d, bool use_high=true); + int hide_cursor; + bool obscure_cursor; + BBitmap *framebuffer; + BView *drawview; + BRegion laregion; + + PortLink *serverlink; +// drawing_mode drawmode; + + rgb_color highcolor,lowcolor; + bool is_initialized; +}; + +#endif \ No newline at end of file