From: David Gow Date: Thu, 17 Apr 2014 02:52:45 +0000 (+0800) Subject: Merge branch 'master' of git.ucc.asn.au:ipdf/code X-Git-Url: https://git.ucc.asn.au/?p=ipdf%2Fcode.git;a=commitdiff_plain;h=67fb91aae1fc5315f462d6b5818806f154e9e687;hp=e12f1118cca4997c895c5ece32900be74f59ecdd Merge branch 'master' of git.ucc.asn.au:ipdf/code --- diff --git a/.gitignore b/.gitignore index 365a631..5041ffa 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ *.test *.out *.err +*.vcd +*.bmp diff --git a/bin/ipdf b/bin/ipdf new file mode 100755 index 0000000..f242971 Binary files /dev/null and b/bin/ipdf differ diff --git a/contrib/vfpu b/contrib/vfpu new file mode 120000 index 0000000..98828c0 --- /dev/null +++ b/contrib/vfpu @@ -0,0 +1 @@ +../../vfpu/bin/vfpu \ No newline at end of file diff --git a/src/Makefile b/src/Makefile index d7247ce..c788f85 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,11 +1,11 @@ #Makefile -ARCH := $(shell uname -i) +ARCH := $(shell uname -m) CXX = g++ -std=gnu++0x -Wall -Werror -Wshadow -pedantic -g MAIN = main.o -OBJ = log.o document.o view.o screen.o +OBJ = log.o document.o view.o screen.o vfpu.o LIB_x86_64 = ../contrib/lib/libSDL2-2.0.so.0 -lGL LIB_i386 = ../contrib/lib32/libSDL2-2.0.so.0 -lGL -LIB_unknown = $(LIB_x86_64) + MAINRPATH_x86_64 = -Wl,-rpath,'$$ORIGIN/../contrib/lib' MAINRPATH_i386 = -Wl,-rpath,'$$ORIGIN/../contrib/lib32' TESTRPATH_x86_64 = -Wl,-rpath,'$$ORIGIN/../../contrib/lib' @@ -14,7 +14,7 @@ OBJPATHS = $(OBJ:%=../obj/%) DEPS := $(OBJPATHS:%.o=%.d) CFLAGS_x86_64 := -I../contrib/include/SDL2 -I`pwd` CFLAGS_i386 := -I../contrib/include32/SDL2 -I`pwd` -CFLAGS_unknown = $(CFLAGS_x86_64) + LIB := $(LIB_$(ARCH)) MAINRPATH := $(MAINRPATH_$(ARCH)) diff --git a/src/ipdf.h b/src/ipdf.h index d6dc955..7150944 100644 --- a/src/ipdf.h +++ b/src/ipdf.h @@ -35,6 +35,13 @@ namespace IPDF } }; + struct Colour + { + float r; float g; float b; float a; + Colour() = default; + Colour(float _r, float _g, float _b, float _a) : r(_r), g(_g), b(_b), a(_a) {} + }; + struct Objects { std::vector types; diff --git a/src/main.cpp b/src/main.cpp index 1b2073e..12d8d56 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,20 +4,66 @@ int main(int argc, char ** argv) { Document doc; srand(time(NULL)); - if (argc > 1) + + enum {OUTPUT_TO_BMP, LOOP} mode = LOOP; + + Rect bounds(0,0,1,1); + Colour c(0,0,0,1); + const char * input_bmp = NULL; + const char * output_bmp = NULL; + const char * input_filename = NULL; + + int i = 0; + while (++i < argc) { - for (int i = 2; i < argc; ++i) + if (argv[i][0] != '-') { - if (fork() == 0) doc.Load(argv[i]); + input_filename = argv[i]; + continue; } - doc.Load(argv[1]); + switch (argv[i][1]) + { + case 'o': + mode = OUTPUT_TO_BMP; + if (++i >= argc) + Fatal("No input argument following -o switch"); + input_bmp = argv[i]; + if (++i >= argc) + Fatal("No output argument following -o switch"); + output_bmp = argv[i]; + + break; + case 'c': + { + Debug("Reading paint colour"); + for (int j = 1; j <= 4; ++j) + { + if (i+j >= argc) + Fatal("No %d colour component following -c switch", j); + char * e; + float * comp = (j == 1) ? (&c.r) : ((j == 2) ? (&c.g) : ((j == 3) ? (&c.b) : &(c.a))); + *comp = strtof(argv[i+j], &e); + if (*e != '\0') + Fatal("Colour component %d not a valid float", j); + } + i += 4; + break; + } + } + } + + if (input_filename != NULL) + { + doc.Load(input_filename); } - else + else { - Debug("Add random object"); - //doc.Add(RECT_FILLED, Rect(Random()*0.5, Random()*0.5, Random()*0.5, Random()*0.5)); - doc.Add(RECT_FILLED, Rect(0.25,0.25, 0.5, 0.5)); + doc.Add(RECT_FILLED, Rect(0.2,0.2,0.6,0.6)); } - MainLoop(doc); + + if (mode == LOOP) + MainLoop(doc, bounds, c); + else if (mode == OUTPUT_TO_BMP) + OverlayBMP(doc, input_bmp, output_bmp, bounds, c); return 0; } diff --git a/src/main.h b/src/main.h index 2346119..6763042 100644 --- a/src/main.h +++ b/src/main.h @@ -3,16 +3,28 @@ #include "document.h" #include "view.h" #include "screen.h" +#include using namespace std; using namespace IPDF; -inline void MainLoop(Document & doc) +inline void OverlayBMP(Document & doc, const char * input, const char * output, const Rect & bounds = Rect(0,0,1,1), const Colour & c = Colour(0.f,0.f,0.f,1.f)) { - View view(doc); + View view(doc, bounds, c); Screen scr; - scr.SetMouseHandler([&](int x, int y, int buttons, int wheel) + //view.Render(); + scr.RenderBMP(input); + scr.Present(); + sleep(5); + scr.ScreenShot(output); +} + +inline void MainLoop(Document & doc, const Rect & bounds = Rect(0,0,1,1), const Colour & c = Colour(0.f,0.f,0.f,1.f)) +{ + View view(doc,bounds, c); + Screen scr; + scr.SetMouseHandler([&](int x, int y, int buttons, int wheel) // [?] wtf { static bool oldButtonDown = false; static int oldx, oldy; @@ -42,6 +54,7 @@ inline void MainLoop(Document & doc) } } ); + while (scr.PumpEvents()) { view.Render(); diff --git a/src/real.h b/src/real.h index 5703671..73aca6d 100644 --- a/src/real.h +++ b/src/real.h @@ -16,41 +16,7 @@ namespace IPDF #elif defined REAL_DOUBLE typedef double Real; inline double Float(Real r) {return r;} -#elif defined REAL_HALF - struct Real - { - Real() = default; - Real(double r) : value(r) - { - int & a = *((int*)(&value)); // um... - // mask out extra bits in exponent - //1000 1111 1000 0000 0000 0011 1111 1111 - // Endianness matters - a &= 0xFFC001F1; //0x8F8003FF; - - } - - Real operator+(float f) const {return Real(value+f);} - Real operator-(float f) const {return Real(value+f);} - Real operator/(float f) const {return Real(value/f);} - Real operator*(float f) const {return Real(value*f);} - Real operator+(const Real & r) const {return Real(this->value + r.value);} - Real operator-(const Real & r) const {return Real(this->value - r.value);} - Real operator*(const Real & r) const {return Real(this->value * r.value);} - Real operator/(const Real & r) const {return Real(this->value / r.value);} - Real & operator+=(const Real & r) {this->value += r.value; return *this;} - Real & operator-=(const Real & r) {this->value -= r.value; return *this;} - Real & operator/=(const Real & r) {this->value /= r.value; return *this;} - Real & operator*=(const Real & r) {this->value *= r.value; return *this;} - - float value; - }; - inline float Float(Real r) {return r.value;} - - inline std::ostream & operator<<(std::ostream & os, Real & r) {return os << r.value;} // yuk - -#endif //REAL_HALF - +#endif } #endif //_REAL_H diff --git a/src/screen.cpp b/src/screen.cpp index 9ee15b4..712bd26 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -18,6 +18,10 @@ Screen::Screen() } m_gl_context = SDL_GL_CreateContext(m_window); + + glClearColor(1.f,1.f,1.f,1.f); + glClear(GL_COLOR_BUFFER_BIT); + Present(); ResizeViewport(800, 600); @@ -80,6 +84,16 @@ bool Screen::PumpEvents() m_mouse_handler(m_last_mouse_x, m_last_mouse_y, 0, evt.wheel.y); } break; + case SDL_KEYDOWN: + { + Debug("Key %c down", (char)evt.key.keysym.sym); + if (isalnum((char)evt.key.keysym.sym)) + { + char filename[] = "0.bmp"; + filename[0] = (char)evt.key.keysym.sym; + ScreenShot(filename); + } + } default: break; } @@ -109,3 +123,88 @@ void Screen::Present() SDL_GL_SwapWindow(m_window); } +void Screen::ScreenShot(const char * filename) const +{ + Debug("Attempting to save BMP to file %s", filename); + + int w = ViewportWidth(); + int h = ViewportHeight(); + unsigned char * pixels = new unsigned char[w*h*4]; + if (pixels == NULL) + Fatal("Failed to allocate %d x %d x 4 = %d pixel array", w, h, w*h*4); + + glReadPixels(0,0,w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + SDL_Surface * surf = SDL_CreateRGBSurfaceFrom(pixels, w, h, 8*4, w*4, 0,0,0,0); + if (surf == NULL) + Fatal("Failed to create SDL_Surface from pixel data - %s", SDL_GetError()); + + GLenum texture_format = (surf->format->Rmask == 0x000000FF) ? GL_RGBA : GL_BGRA; + Debug("SDL_Surface %d BytesPerPixel, format %d (RGB = %d, BGR = %d, RGBA = %d, BGRA = %d)", surf->format->BytesPerPixel, texture_format, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA); + + if (SDL_SaveBMP(surf, filename) != 0) + Fatal("SDL_SaveBMP failed - %s", SDL_GetError()); + + SDL_FreeSurface(surf); + delete [] pixels; + Debug("Succeeded!"); +} + +/** + * Render a BMP + * NOT PART OF THE DOCUMENT FORMAT + */ +void Screen::RenderBMP(const char * filename) const +{ + SDL_Surface * bmp = SDL_LoadBMP(filename); + if (bmp == NULL) + Fatal("Failed to load BMP from %s - %s", filename, SDL_GetError()); + + int w = bmp->w; + int h = bmp->h; + + GLenum texture_format; + switch (bmp->format->BytesPerPixel) + { + case 4: //contains alpha + texture_format = (bmp->format->Rmask == 0x000000FF) ? GL_RGBA : GL_BGRA; + break; + case 3: //does not contain alpha + texture_format = (bmp->format->Rmask == 0x000000FF) ? GL_RGB : GL_BGR; + break; + default: + Fatal("Could not understand SDL_Surface format (%d colours)", bmp->format->BytesPerPixel); + break; + } + + //Debug("SDL_Surface %d BytesPerPixel, format %d (RGB = %d, BGR = %d, RGBA = %d, BGRA = %d)", bmp->format->BytesPerPixel, texture_format, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA); + + + GLuint texID; + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &texID); + glBindTexture(GL_TEXTURE_2D, texID); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glTexImage2D(GL_TEXTURE_2D, 0, bmp->format->BytesPerPixel, w, h, 0, texture_format, GL_UNSIGNED_BYTE, bmp->pixels); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0, 1.0, 1.0, 0.0, -1.f, 1.f); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glBegin(GL_QUADS); + glTexCoord2i(0,0); glVertex2f(0,0); + glTexCoord2i(1,0); glVertex2f(1,0); + glTexCoord2i(1,1); glVertex2f(1,1); + glTexCoord2i(0,1); glVertex2f(0,1); + glEnd(); + + glDisable(GL_TEXTURE_2D); + SDL_FreeSurface(bmp); +} diff --git a/src/screen.h b/src/screen.h index 4d92cb3..e641826 100644 --- a/src/screen.h +++ b/src/screen.h @@ -24,8 +24,8 @@ namespace IPDF void Present(); // Get the current width/height of the window's viewport. - int ViewportWidth() { return m_viewport_width; } - int ViewportHeight() { return m_viewport_height; } + int ViewportWidth() const { return m_viewport_width; } + int ViewportHeight() const { return m_viewport_height; } // Handle mouse input. typedef std::function MouseHandler; @@ -43,6 +43,9 @@ namespace IPDF CursorHand }; void SetMouseCursor(MouseCursors cursor); + + void ScreenShot(const char * filename) const; + void RenderBMP(const char * filename) const; private: void ResizeViewport(int width, int height); diff --git a/src/tests/repr.cpp b/src/tests/repr.cpp new file mode 100644 index 0000000..26ed668 --- /dev/null +++ b/src/tests/repr.cpp @@ -0,0 +1,33 @@ +#include "main.h" + +#include + +using namespace std; + + + +int main(int argc, char ** argv) +{ + char buffer[BUFSIZ]; + double input; + printf("Enter a double: "); + fgets(buffer, BUFSIZ, stdin); + sscanf(buffer, "%lf", &input); + + + float f = (float)(input); + + unsigned long long i; + memcpy(&i, &f, 4); + bitset<32> b32(i); + memcpy(&i, &input, 8); + bitset<64> b64(i); + + printf("\nAs float: %s\n", b32.to_string().c_str()); + printf("\nAs double: %s\n", b64.to_string().c_str()); + #ifdef REAL_BITSET + Real r(input); + printf("\nAs real: %s\n", r.repr.to_string().c_str()); + #endif //REAL_BITSET + +} diff --git a/src/tests/vfpufloat.cpp b/src/tests/vfpufloat.cpp new file mode 100644 index 0000000..dae457b --- /dev/null +++ b/src/tests/vfpufloat.cpp @@ -0,0 +1,18 @@ +#include "main.h" + +#include "vfpu.h" +using namespace std; + + +int main(int argc, char ** argv) +{ + if (argc > 1) + VFPU::Start(argv[1]); + else + VFPU::Start(); + float result = VFPU::Exec(25,10, VFPU::SUB); + Debug("%f\n", result); + VFPU::Halt(); + + return 0; +} diff --git a/src/vfpu b/src/vfpu new file mode 120000 index 0000000..2fcb913 --- /dev/null +++ b/src/vfpu @@ -0,0 +1 @@ +../contrib/vfpu \ No newline at end of file diff --git a/src/vfpu.cpp b/src/vfpu.cpp new file mode 100644 index 0000000..8783ca1 --- /dev/null +++ b/src/vfpu.cpp @@ -0,0 +1,148 @@ +#include "vfpu.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "common.h" + +using namespace std; + +namespace VFPU +{ + +static const char g_fpu[] = "vfpu"; + +static bool g_running = false; +static int g_fpu_socket[2] = {-1,-1}; +static pid_t g_fpu_pid = -1; + +/** + * Starts the VFPU + * @returns 0 on success, errno of the failing function on failure + */ +int Start(const char * vcd_output) +{ + assert(!g_running); + // create unix socket pair + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, g_fpu_socket) != 0) + return errno; + + + g_fpu_pid = fork(); + if (g_fpu_pid < 0) // error check + return errno; + + + // Child branch + if (g_fpu_pid == 0) + { + + // Remap stdio to the socket + dup2(g_fpu_socket[0],fileno(stdin)); + dup2(g_fpu_socket[0],fileno(stdout)); + + // Unbuffer things; buffers are a pain + setbuf(stdin, NULL); setbuf(stdout, NULL); setbuf(stderr, NULL); + + Debug("Child about to suppress stderr and exec vfpu"); + dup2(open("/dev/null", O_APPEND), fileno(stderr)); //LALALA I AM NOT LISTENING TO YOUR STUPID ERRORS GHDL + if (vcd_output != NULL) + { + string s("--vcd="); + s += vcd_output; + execl(g_fpu, g_fpu, s.c_str(), NULL); + } + else + { + execl(g_fpu, g_fpu,NULL); + } + int err = errno; // Because errno will be set again by the next system call + Fatal("Uh oh! %s\n", strerror(err)); // We will never see this if something goes wrong... oh dear + exit(err); // Child exits here. + } + + // Parent branch + usleep(100); + g_running = true; // We are ready! + return 0; +} + +/** + * Halt the VFPU + */ +int Halt() +{ + assert(g_running); + // Tell the child to stop running the VHDL simulation + if (close(g_fpu_socket[1]) != 0) + return errno; + usleep(1000); + if (kill(g_fpu_pid, SIGKILL) != 0) + return errno; + g_running = false; + return 0; +} + +float Exec(float opa, float opb, Opcode op, Rmode rmode) +{ + unsigned a; memcpy(&a, &opa, sizeof(float)); + unsigned b; memcpy(&b, &opb, sizeof(float)); + + unsigned r = (unsigned)(Exec(Register(a), Register(b), op, rmode).to_ulong()); + float result; memcpy(&result, &r, sizeof(float)); + return result; +} + +/** + * Tell the VFPU to execute an instruction, wait for it to finish, return the result + * TODO: Make this not mix C++ and C so badly? + * TODO: It will still only work for magic 32 bit FPU + */ +Register Exec(const Register & a, const Register & b, Opcode op, Rmode rmode) +{ + assert(g_running); + + stringstream s; + s << hex << setw(8) << setfill('0') << a.to_ullong() << "\n" << b.to_ullong() << "\n" << setw(1) << op <<"\n" << setw(1) << rmode << "\n"; + string str(s.str()); + //Debug("Writing: %s", str.c_str()); + + // So we used C++ streams to make our C string... + assert(write(g_fpu_socket[1], str.c_str(), str.size()) == (int)str.size()); + + char buffer[BUFSIZ]; + int len = read(g_fpu_socket[1], buffer, sizeof(buffer)); + //assert(len == 9); + buffer[--len] = '\0'; // Get rid of newline + //Debug("Read: %s", buffer); + + Register result(0); + for (int i = 0; i < len/2; ++i) + { + unsigned byte; // It is ONE byte (2 nibbles == 2 hex digits) + sscanf(buffer+2*i, "%02x", &byte); + result |= (byte << 8*(len/2-i-1)); + } + + stringstream s2; + s2 << hex << result.to_ullong(); + //Debug("Result is: %s", s2.str().c_str()); + return result; +} + +} + + diff --git a/src/vfpu.h b/src/vfpu.h new file mode 100644 index 0000000..12ac9bc --- /dev/null +++ b/src/vfpu.h @@ -0,0 +1,35 @@ +#ifndef _VFPU_H +#define _VFPU_H + +/** + * Implements a terrible and hacky interface to use a virtual FPU to do floating point operations + */ + +#include + +namespace VFPU +{ + extern int Start(const char * vcd_output = NULL); // Starts the VFPU + extern int Halt(); // Halts the VFPU + +/** + -- 000 = add, + -- 001 = substract, + -- 010 = multiply, + -- 011 = divide, + -- 100 = square root + -- 101 = unused + -- 110 = unused + -- 111 = unused + */ + typedef enum {ADD=0x000, SUB=0x001, MULT=0x010, DIV=0x011, SQRT=0x100} Opcode; + typedef enum {EVEN=0x00, ZERO=0x01, UP=0x10, DOWN=0x11} Rmode; + typedef std::bitset<32> Register; + + extern Register Exec(const Register & a, const Register & b, Opcode op, Rmode rmode = EVEN); // operate with registers + extern float Exec(float a, float b, Opcode op, Rmode rmode = EVEN); //converts floats into registers and back +} + +#endif //_VFPU_H + + diff --git a/src/view.cpp b/src/view.cpp index 969bbb3..3c6e2f5 100644 --- a/src/view.cpp +++ b/src/view.cpp @@ -35,6 +35,31 @@ void View::ScaleAroundPoint(Real x, Real y, Real scaleAmt) m_bounds.h *= scaleAmt; } +void View::DrawGrid() +{ + // Draw some grid lines at fixed pixel positions + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0, 1.0, 1.0, 0.0, -1.f, 1.f); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glColor4f(0.9,0.9,0.9,0.1); + const float num_lines = 50.0; + for (float i = 0; i < num_lines; ++i) + { + glBegin(GL_LINES); + glVertex2f(i*(1.0/num_lines), 0.0); + glVertex2f(i*(1.0/num_lines), 1.0); + glEnd(); + glBegin(GL_LINES); + glVertex2f(0.0,i*(1.0/num_lines)); + glVertex2f(1.0,i*(1.0/num_lines)); + glEnd(); + + } +} + void View::Render() { static bool debug_output_done = false; @@ -47,13 +72,15 @@ void View::Render() glClearColor(1.f,1.f,1.f,1.f); glClear(GL_COLOR_BUFFER_BIT); + //DrawGrid(); // Draw the gridlines + glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(Float(m_bounds.x), Float(m_bounds.x)+Float(m_bounds.w), Float(m_bounds.y) + Float(m_bounds.h), Float(m_bounds.y), -1.f, 1.f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - glColor4f(0.f,0.f,0.f,1.f); + glColor4f(m_colour.r, m_colour.g, m_colour.b, m_colour.a); glBegin(GL_QUADS); for (unsigned id = 0; id < m_document.ObjectCount(); ++id) { @@ -67,6 +94,7 @@ void View::Render() } glEnd(); + for (unsigned id = 0; id < m_document.ObjectCount(); ++id) { if (m_document.m_objects.types[id] != RECT_OUTLINE) diff --git a/src/view.h b/src/view.h index 6b63799..24ae6d9 100644 --- a/src/view.h +++ b/src/view.h @@ -9,7 +9,8 @@ namespace IPDF class View { public: - View(Document & document) : m_document(document), m_bounds(0,0,1,1) {} + View(Document & document, const Rect & bounds = Rect(0,0,1,1), const Colour & colour = Colour(0.f,0.f,0.f,1.f)) + : m_document(document), m_bounds(bounds), m_colour(colour) {} virtual ~View() {} void Render(); @@ -18,8 +19,10 @@ namespace IPDF void ScaleAroundPoint(Real x, Real y, Real scaleAmt); private: + void DrawGrid(); Document & m_document; Rect m_bounds; + Colour m_colour; }; }