Jump to content
orbs

advice on compiling a c++ project to a standalone console executable

Recommended Posts

for a savvy c++ developer, how hard would it be to compile this into a standalone Win32 console executable?

i have almost no experience with c++ (and i have no need for any more, since i have AutoIt for pretty much all my requirements). i can compile a simple "hello world" executable (and even embed the mfc dll for backward compatibility). but i am quite interested with that project. your opinion?

 

P.S. this relates to AutoIt quite simply - once (if and when) i have that project as a standalone executable, i have a GUI made with AutoIt to execute it, then post-process and display the output.

 

Share this post


Link to post
Share on other sites
Posted (edited)

so i looked into building the cpp dll, but it's deprecated and VERY slow because in the port they used a dependency for QT library. They are not maintaining support. I have the C# stuff built, and using @LarsJ threads on running compiled .NET code, this could work for you. this is a visual studio project. The zip is too big to fit here though. Let me know if you want it. I can enable a OneDrive link for the download.

 

Capture.png

just updated it to use .net 4.7.2 and now it's even faster... lol, love this. makes a usable dll

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
Posted (edited)

ok, got something working. with the console app you can specify two files to compare, and they can contain paths if needed (unless running where files are located of course)in su and you can pipe the console output or capture it.

this contains Speedtest.exe and DiffMatchPatch.dll. 

runs on windows 10, not tested elsewhere, build with .NET 4.7.2, should work on out of box 4.6

 use it like this or capture the output, your choice, but all they offer with this is html diff results

to pipe it to a file

speedtest SpeedTest1.txt SpeeTest2.txt > diffs.html

or plain console output

speedtest SpeedTest1.txt SpeeTest2.txt

one more thing, needs work on validating args, so if you feed it two you are ok with my simple checker, problem is, if one of those files is misspelt, then it will CRASH, lol, can be fixed. need input.

using dotnetcore to build this you could make it run native on many Linux distros, including all the big names and lots of little ones. i just used the google test cs app... lol and modified for my purposes. but that is how i roll, don't like re-inventing stuff.

to distribute or use, you only need the EXE, the DLL file

 

 

DiffMatchPatch_SpeedTest.zip

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites

thank you @Earthshine for this incredible work.

i must confess, what you have done is waaaaaaay over my head. therefore i limit myself to the conceptual aspect. i have downloaded and tested your code, and some questions do arise:

* the dll you build - can it be called directly from AutoIt using DllCall()? if so, how? and would it return an array of elements (which can be post-processed), or the final HTML formatted output?

* the diff demo has some post-diff cleanup settings which can be configured: Semantic, Efficiency, or none. as per my tests, your compilation seems to be using no cleanup. the demo offers Semantic cleanup which is better for human readability, and Efficiency cleanup (with edit cost of 4 by default, but with 5 it seems identical to Semantic). when i read the source code for the C# library, i see that these behaviour settings have default values (lines 181 to 201), and that these can be set by the calling process (line 183). have you some idea how to pass custom values to the dll for these settings?

PS. when you build the dll, the "File description" property has a typo ("DiffMatchPach" - missing a "t" for the "Patch" part). is this you, or is this specified somewhere in the source code? not that i mind so much, i'm just trying to figure out the logic of things.

PS2. i initially opted for C++ rather than C# because i'm allergic to anything dependent on .NET (being a sysadmin and all ;)). have you any information on whether this compilation has indeed .NET dependency, and if so, which version?

 

Share this post


Link to post
Share on other sites
Posted (edited)

I don't think you can use DllCall() on this, as it's a .NET DLL

I have not yet figured out if it can be called direct by AutoIT, as I have tried using @LarsJ dotnet UDF

we can make the console app better to allow the configuration settings, let me look into that. Also the argument checking and validation need serious attention in the console app to make it usable, and we can add args to make those settings changes you wanted if we can.

I can easily add this line of code to console for you

diff_cleanupSemantic(diffs);

It's in Speedtest.cs, if you change that, we can get you to build it (.NET built in compiler if you you have .NET installed) and run that console app.

 

 

 

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
Posted (edited)

it's good, because some people or organisations stay on a certain one sometimes, so, I like the idea. My dll is the google code dll, but you can use thiers and modify the console app to your liking. I will help with that of course. so let me work on those changes to the console until we figure out how to use them direct. I built mine with the latest .NET available to me. 4.7.2, they just depend on 4.5, which is cool because it will run on 4.5 and up.

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites

so i am going to update the .cs file and exe output to the post above, it includes those things you wanted to make it more readable

// Copyright 2010 Google Inc.
// All Right Reserved.

using DiffMatchPatch;
using System;
using System.Collections.Generic;




public class Speedtest
{
    public static void Main(string[] args)
    {
        //       string text1 = System.IO.File.ReadAllText("Speedtest1.txt");
        //       string text2 = System.IO.File.ReadAllText("Speedtest2.txt");

        if (args.Length < 2)
        {
            Console.WriteLine(value: "ERROR: args = null please provide two valid files you wish to compare.");
            /*            if (IsLinux())
                        {
                            Console.WriteLine(value: "Example: list / *.cpp");
                        }
                        else
                        {
                            Console.WriteLine(value: "Example: list c:\\ *.dll");
                        }
            */
        }
        else
        {

            string text1 = System.IO.File.ReadAllText(args[0]);
            string text2 = System.IO.File.ReadAllText(args[1]);

            diff_match_patch dmp = new diff_match_patch();
            dmp.Diff_Timeout = 0;

            var diffs = dmp.diff_main(text1, text2);
            dmp.diff_cleanupSemantic(diffs);
            var html = dmp.diff_prettyHtml(diffs);

            Console.WriteLine(html.ToString());

        }
    }
}

as you can see the input arguments should be properly validated and that needs to happen still,


My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites

Some good news, I was able to figure out, thanks to @Larsj -- that you can pass arrays of arguments to .NET code. So I think we can load DiffMatchPatch.cs into memory (compiles it on the fly) and then use the class in AutoIt

I just need to get a list of the DLLs it needs to load so I can test it, then you can call whatever method you want direct from AU3


My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
Posted (edited)

I have tried everything, but I think it won't work direct because I can't represent the return value of diff_main method properly, but using the console exe and the dll together, this gets the string, you could regex it and get out all the data. I have included this file in the zip, called SpeedTestWrapper, all this is just development, can be altered and beefed up per specs if given.

#include <Array.au3>

Opt("MustDeclareVars", 1)
Example()

Func Example()
    Local $iPID = Run(@ComSpec & " /c Speedtest.exe SpeedTest1.txt SpeedTest2.txt > test.html")

    Local $oDiffs = FileReadToArray ("test.html")
    _ArrayDisplay($oDiffs)
EndFunc

I updated my post above to include what's necessary

https://www.autoitscript.com/forum/applications/core/interface/file/attachment.php?id=60787

you won't need the DiffMatchPatchTest.exe, all that does is unit test the DLL, at the console it should return "All Tests Passed" you can ignore that cs file and exe

 

Like I said, the speedtest.cs can be renamed to what you want, and we can beef up the arguments passed so you can totally configure the diff produced, which is only html in a string for you to parse

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites

@Earthshine, i'm sorry i cannot contribute to that work you have done - which is awesome!

myself being reluctant of dependencies, and of not understanding or being able to maintain the code, i took a different path - that of the python. the GitHub repository includes the library in many languages, python being one of them, and i discovered python is surprisingly easy to learn (definitely so for AutoIt users). so i created a python program, compiled it to a single exe with its only dependency is the msvcr dll - the one shipped with Windows XP SP2 works out of the box - so no compatibility issues. now working on the command line arguments parsing - also not hard. i will post what i have when done (and when it doesn't look like spaghetti code :-)

Share this post


Link to post
Share on other sites
Posted (edited)

i did a lot of python in TestComplete, my little logger rules. if you want it, you can have it. here it is. I hope you find it as useful as I did. I basically got it from the logging example in their help documentation and I think it was gold... worked great. your scripts just import from logging

import logging
from logging import NullHandler
import Const

def startLog(name):
  logger = logging.getLogger(name)
  logger.setLevel(logging.DEBUG)
  # create file handler which logs even debug messages
  fh = logging.FileHandler(Const.TD_LOGFILE)
  fh.setLevel(logging.DEBUG)
  # create console handler with a higher log level
  ch = logging.StreamHandler()
  ch.setLevel(logging.ERROR)

  ch1 = logging.StreamHandler()
  ch1.setLevel(logging.WARN)
  # create formatter and add it to the handlers
  formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  ch.setFormatter(formatter)
  ch1.setFormatter(formatter)
  fh.setFormatter(formatter)
  # add the handlers to logger
  logger.addHandler(ch)
  logger.addHandler(ch1)
  logger.addHandler(fh)    

  return logger

I call that LogUtil.py

 

then you can use this to log all the arguments passed to your functions, I love Reflection! a real OOP like Python rules

from os import sys
sys.path.append('C:\\Python34x86\\Lib\\site-packages')
import psutil
import logging
import Const
import inspect
import datetime
import time


def delay(seconds):
  Delay(seconds)
  
def logArgValues(frame):
  args, _, _, values = inspect.getargvalues(frame)
  for i in args:
    try :  
      Log.Message ("    %s = %s" % (i, values[i]))    
    except :
      pass
  return

with the logger, you just use it like this

logger.Message(log message text here)

logger.Warning(log message text here)

logger.Error(log message text here)

logger.Trace(log message text here)

you can totally customize the logger to include TRACE, currently only implemented Warning, Debug and 

 

Object oriented languages are my favorite for a reason.

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites

whoa, that's still a bit over my head (again...) - but i might revisit that if and when i get to something that needs decent logging... meanwhile, what i did for this project is a tad bit more simple. it accepts two files as parameters, passes them to the diff-match-patch library, and reformats the output:

''' arguments:
if <2 or >3 : show general help & exit 9
if error reading #1,#2 : show specific cause & exit 8,7
if #3 not specified : output to stdout
if #3 specified but error opening it for writing: show specific cause & exit 6
'''

msg_help=""

msg_help+="\n"
msg_help+="program:   diffdmp.exe\n"
msg_help+="type:      Win32 console application\n"
msg_help+="version:   1.0\n"
msg_help+="\n"
msg_help+="purpose:   compare two text files (typically two versions of a text) using\n"
msg_help+="           the diff-match-patch library, with semantic cleanup. produce an\n"
msg_help+="           ordered list of additions, removals and identical text sections\n"
msg_help+="           which allows for clear presentation of the differences, as well\n"
msg_help+="           as recreating each of the texts.\n"
msg_help+="\n"
msg_help+="reference: https://github.com/google/diff-match-patch\n"
msg_help+="\n"
msg_help+="usage:     diffdmp.exe older_file newer_file [diffs_file]\n"
msg_help+="\n"
msg_help+="arguments: older_file : the first file to diff (typically the older version).\n"
msg_help+="           newer_file : the other file to diff (typically the newer version).\n"
msg_help+="           diffs_file : [optional] where to output the result. default=stdout"

import sys

if len(sys.argv)<3 or len(sys.argv)>4:
    print(msg_help)
    sys.exit(9)

try:
    text1 = open(sys.argv[1]).read()
except IOError:
    print("Error reading the older file:",sys.argv[1])
    sys.exit(8)

try:
    text2 = open(sys.argv[2]).read()
except IOError:
    print("Error reading the newer file:",sys.argv[2])
    sys.exit(7)

if len(sys.argv)==4:
    try:
        diffs_file=open(sys.argv[3],"w")
    except IOError:
        print("Error writing to diffs file:",sys.argv[3])
        sys.exit(6)
else:
    diffs_file=sys.stdout

'''
main function
'''

import diff_match_patch as dmp_module

dmp = dmp_module.diff_match_patch()
dmp.Diff_Timeout = 0.0
  
diffs = dmp.diff_main(text1, text2, False)
dmp.diff_cleanupSemantic(diffs)

'''
output
'''

diffchar=["-","=","+"]

for diff in diffs:
    print(diffchar[diff[0]+1]+str(len(diff[1]))+":"+diff[1], end='', file=diffs_file)

i wrote this with python 3.4 on Windows XP (clean installation with SP2), then compiled it with PyInstaller (made a resource file with version details in it and stuff, added a simple cmd icon) - and it works! and no messing about with compatibility of dependencies! even with a rather old msvcr*.dll it works out of the box!

me be happy.

P.S. will test further to see if adjustment of parameters is needed, if so i can easily add them to the arguments parsing routine.

P.S.2 if you see anything extremely dumb in my code above, do feel free to point it out. my first python script and all...

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • By jamesbowers
      Hi guys! I have a problem that i hope you give me an advice to solve it. I have writing this code and it doesn't run cuz its a problem.
      C2562 'Draw':'void' function returning a vaue.....
      I dont know what to correct.
       

    • By Dragonfighter
      Autoit version: 3.3.14.5
      System: Windows 10 Home x64
      C++ IDE: Code::Blocks 17.12
      When I call the Dll that I wrote it give me how return value -1073741819 and exit value 3221225477, I tried changing variables type but it didn't work.
      This is the Autoit code:
      #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=n #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** $dll = DllOpen(@ScriptDir & "\Test.dll") DllCall($dll, "NONE", "TestFunction", "STR", "1 string", "STR", "2 string", "STR", "3 string", "INT", 1) ;Here crash and doesn't show the MsgBox MsgBox(0, "", @error) DllClose($dll) This is the main.cpp code:
      #include <iostream> #include <Windows.h> #include "main.h" using namespace std; extern "C" { DECLDIR void TestFunction(std::string string1, std::string string2, std::string string3, int number1) { std::cout << string1 << std::endl; std::cout << string2 << std::endl; std::cout << string3 << std::endl; std::cout << number1 << std::endl; } } And that is the main.h:
      #ifndef _DLLTEST_H_ #define _DLLTEST_H_ #define DLL_EXPORT #if defined DLL_EXPORT #define DECLDIR __declspec(dllexport) #else #define DECLDIR __declspec(dllimport) #endif extern "C" { DECLDIR void TestFunction(std::string string1, std::string string2, std::string string3, int number1); } #endif  
      And the values of the variables that write to the SciTe console ae completely different.
      Here I attach the console output of the SciTe editor:
      >"C:\Program Files (x86)\AutoIt3\SciTE\..\AutoIt3.exe" "C:\Program Files (x86)\AutoIt3\SciTE\AutoIt3Wrapper\AutoIt3Wrapper.au3" /run /prod /ErrorStdOut /in "C:\Users\DragonFighter\Desktop\Dll test.au3" /UserParams +>10:30:08 Starting AutoIt3Wrapper v.17.224.935.0 SciTE v.3.7.3.0 Keyboard:00000410 OS:WIN_10/ CPU:X64 OS:X64 Environment(Language:0410) CodePage:0 utf8.auto.check:4 +> SciTEDir => C:\Program Files (x86)\AutoIt3\SciTE UserDir => C:\Users\DragonFighter\AppData\Local\AutoIt v3\SciTE\AutoIt3Wrapper SCITE_USERHOME => C:\Users\DragonFighter\AppData\Local\AutoIt v3\SciTE >Running AU3Check (3.3.14.5) from:C:\Program Files (x86)\AutoIt3 input:C:\Users\DragonFighter\Desktop\Dll test.au3 +>10:30:08 AU3Check ended.rc:0 >Running:(3.3.14.5):C:\Program Files (x86)\AutoIt3\autoit3.exe "C:\Users\DragonFighter\Desktop\Dll test.au3" --> Press Ctrl+Alt+Break to Restart or Ctrl+Break to Stop �Á+���Uø‰q�‰A�‹O`ÆEÿ�èèÖÿÿƒÄ €}ÿ!>10:30:10 AutoIt3.exe ended.rc:-1073741819 +>10:30:10 AutoIt3Wrapper Finished. >Exit code: 3221225477 Time: 3.414  
      Thanks in advance for every reply.
    • By marcoauto
      Ciao
      I would like to control an ATEM Video Mixer from autoit. I downloaded his SDK which is written in c ++ and I found the sequences to interface, but I was not able to convert the script to self.
      The instructions say to follow this sequence:
      and to connectTo with C++ is:
      string address = "192.168.1.240"; _BMDSwitcherConnectToFailure failureReason = 0; IBMDSwitcher switcher = null; var discovery = new CBMDSwitcherDiscovery(); discovery.ConnectTo(address, out switcher, out failureReason); From Blackmagic SDK:
      IBMDSwitcherDiscovery::ConnectTo method
      The ConnectTo method connects to the specified switcher and returns an IBMDSwitcher object interface for the switcher.
      Syntax HRESULT ConnectTo (string deviceAddress, IBMDSwitcher** switcherDevice, BMDSwitcherConnectToFailure* failReason); Parameters: deviceAddress in Network hostname or IP address of switcher to connect to. switcherDevice out IBMDSwitcher object interface for the connected switcher. failReason out Reason for connection failure as a BMDSwitcherConnectToFailure value. So, I have I tried these solutions but with non success:
      $DllName =@ScriptDir&"\BMDSwitcherAPI.dll" $result = DllCall($DllName, "none", "IBMDSwitcherDiscovery::ConnectTo" & @CRLF) ConsoleWrite("DLLCall Result: " & $result & @CRLF) and I have tried also create an Object (That I think is the best way solution):
      #include <MsgBoxConstants.au3> $oSwitcher=ObjCreate("IBMDSwitcher") If IsObj($oSwitcher) Then MsgBox(64, "", "Object $oSwitcher created successfully") EndIf $oAtem=ObjCreate("IBMDSwitcherDiscovery") If IsObj($oAtem) Then MsgBox(64, "", "Object $oAtem created successfully") EndIf $failureReason =ObjCreate("_BMDSwitcherConnectToFailure") If IsObj($failureReason) Then MsgBox(64, "", "Object $failureReason created successfully") EndIf $oMyError = ObjEvent("AutoIt.Error", "MyErrFunc") ; Install a custom error handler Global $errore,$oSwitcher1 $oAtem.ConnectTo("192.168.1.36",$oSwitcher,$failureReason); ; This is the custom error handler Func MyErrFunc() $HexNumber = Hex($oMyError.number, 8) MsgBox(0, "", "We intercepted a COM Error !" & @CRLF & _ "Number is: " & $HexNumber & @CRLF & _ "Windescription is: " & $oMyError.windescription & @CRLF & _ "Source is: " & $oMyError.source & @CRLF & _ "Description is: " & $oMyError.description & @CRLF & _ "Helpfile is: " & $oMyError.helpfile & @CRLF & _ "Helpcontext is: " & $oMyError.helpcontext & @CRLF & _ "Lastdllerror is: " & $oMyError.lastdllerror & @CRLF & _ "Scriptline is: " & $oMyError.scriptline) EndFunc ;==>MyErrFunc But the result is:
      We intercepted a COM Error !
      Number is: 000000A9
      Windescription is: Variable must be of type 'Object'.
      Source is: 
      Description is: 
      Helpfile is: 
      Helpcontext is: 
      Lastdllerror is: 0
      Scriptline is: 17
      The BMDSwitcherAPI.dll is registered in system. Can someone help me?
      Grazie
      Marco
    • By Dragonfighter
      #include <iostream> #include <fstream> #include <string> int main () { std::ifstream is ("image.png", std::ifstream::binary); unsigned char buffer_array[4][4]; if (is) { is.seekg (0, is.end); int length = is.tellg(); is.seekg (0, is.beg); char * buffer = new char [length]; is.read (buffer,length); //Here I get the error unsigned char * buffer_str=buffer; for (int count1=0; count1<4; count1=count1+1) { for (int count2=0; count2<4; count2=count2+1) { //Here I get the others two errors buffer_array[count1][count2]=buffer_str.substr(0, 2); buffer_str.erase(0, 2) }; }; return 0; }; }; My goal is to split the binary buffer of the image.png in an array, I tried using string modifiers but I get two errors: request for member 'erase' in 'buffer_str', which is of non-class type 'unsigned char*' thats what I get when build.
       
       
    • By Xandy
      I wanted to start using SDL2 libraries in C++.
      This is a Hello World project that covers some of the essentials of programming with SDL2.
      I will use it when I forget how to create an SDL2 project.
      Loads a scrolling background image for world. Mouse position, left click, and double click example. Hotkeys and cooldown timers to prevent hotkey spam. Plays background music. (ALT + P) Plays sound effects changing sprite type. (numpad: /, *, -, +) Features a Player class for multiplayer. Player collision detection. Uses a Window class from Lazyfoo for maximize button, fullscreen ext.. Built using MSVS 2013 (free).  All dlls and libraries included and linked (for MSVS) using relative paths. You can probably run the SDL2_HelloWorld.sln without setting up any libraries. Note SDL_Net is setup but not used. Delta time used to create consistent frame rate across machines. Player animation sprite sheet:  
      Demo: Slimy's First Kiss
      Download Source and project: http://songersoft.com/programming/sdl2_helloworld/sdl2_helloworld_about.phtml
      This isn't meant to be amazing.  It's just to help get started with SDL2.
      I will consider any criticism.
      main.cpp
      // This example HelloWorld followed this video: // https://www.youtube.com/watch?v=M4Jgz0wEQxY // Turned into this // https://www.youtube.com/watch?v=yRpen8jOa08&list=PL77-op_SRaiEuC0YC43ZAUJJwL_G_C2z8&index=15 // Window class was copied from Lazyfoo // http://lazyfoo.net/tutorials/SDL/35_window_events/index.php #include <iostream> #include <string> #include "SDL.h" #include "SDL_image.h" #include "SDL_ttf.h" #include "SDL_mixer.h" #include "SDL_net.h" #include "Player.h" #include "Window.h" using namespace std; // Prototypes SDL_Texture *LoadTexture(string filepath, SDL_Renderer *renderTarget); void logSDLError(const string); SDL_Rect sdlrect(int, int, int, int); SDL_Surface *OptimizedSurface(string filepath, SDL_Surface *windowSurface); // if(okAlt) either Alt key is pressed OrKeyALT #define okAlt (k[SDL_SCANCODE_RALT] || k[SDL_SCANCODE_LALT]) int main(int argc, char *argv[]) { // Needed for the initialize block Window window; SDL_Renderer *renderTarget = nullptr; // Initialize SDL2 if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { logSDLError("SDL_Init "); } // Initialize SDL_image if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) { cout << "Could not initialize SDL_image: " << IMG_GetError() << std::endl; SDL_Delay(5500); } // Initialize TTF if (TTF_Init() < 0) cout << "TTF_Init " << TTF_GetError() << endl; //Create window if (!window.init("SDL2 Hello World", 640, 480, "../../Graphics/iconbmp.bmp")) { printf("Window could not be created! SDL Error: %s\n", SDL_GetError()); } else { //Create renderer for window renderTarget = window.createRenderer(); if (renderTarget == NULL) { printf("Renderer could not be created! SDL Error: %s\n", SDL_GetError()); } } // Audio if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) { cout << "Mix_OpenAudio: " << Mix_GetError() << endl; } // Load sounds: Run chunk if less than 10 sec, music if greater (generally) //Mix_Music *bgm = Mix_LoadMUS("../../Sounds/overworld.mid"); // Can't Pause MIDI Mix_Music *bgm = Mix_LoadMUS("../../Sounds/bensound-goinghigher.mp3"); cout << Mix_GetError() << endl; // Font and text SDL_Texture *text_texture = nullptr; SDL_Color textColor = { 144, 77, 255, 255 }; TTF_Font *font = TTF_OpenFont("../../Graphics/Fonts/VCR_OSD_MONO.ttf", 20); if (font) { SDL_Surface *textSurf = TTF_RenderText_Solid(font, "Hello world", textColor); text_texture = SDL_CreateTextureFromSurface(renderTarget, textSurf); SDL_FreeSurface(textSurf); } else cout << TTF_GetError() << endl; SDL_Rect textRect = { 0, 0, 0, 0 };// Position of text on window // Get the size of the text_texture SDL_QueryTexture(text_texture, NULL, NULL, &textRect.w, &textRect.h); const int playerMax = 8; int players = 2; float prevTime = 0, currentTime = 0, deltaTime = 0; bool fullscreen_toggle = 0; int i = 0, ii = 0; int redraw = 1; bool done = 0; // Load player sprite sheet and background texture SDL_Texture *spritesheet_texture = LoadTexture("../../Graphics/DW3_Char_SpriteSheet.png", renderTarget); SDL_Texture *bg_texture = LoadTexture("../../Graphics/dw3-over.png", renderTarget); int bg_texture_w = 0, bg_texture_h = 0; // Point k to Keyboard state (only needs done here, not in main loop) const Uint8 *k = SDL_GetKeyboardState(NULL); SDL_Event windowEvent; // Stop keys spamming (like music ON / OFF) float key_cooldown_timer_max = 500.0f, key_cooldown_timer = 0; SDL_Rect cameraRect = { 0, 0, window.getWidth(), window.getHeight()}; // Construct default players Player player[playerMax]; // Customize players (texture and position) for (i = 0; i < players; i++)//(sprite texture, position x, position y) player[i].Player_new(spritesheet_texture, window.getWidth() / 2 + i * 16, window.getHeight() / 2); // Get the size of bg_texture SDL_QueryTexture(bg_texture, NULL, NULL, &bg_texture_w, &bg_texture_h); // Main message loop while (!done) { prevTime = currentTime; currentTime = SDL_GetTicks(); deltaTime = (currentTime - prevTime) / 1000.0f; while (SDL_PollEvent(&windowEvent) != 0) { // Check for events if (windowEvent.type == SDL_QUIT) { // Window Exit done = 1; } else if(windowEvent.type == SDL_MOUSEBUTTONDOWN) { // Mouse buttons if (windowEvent.button.clicks == 2) { // Double left click redraw = 1; } else if (windowEvent.button.button == SDL_BUTTON_LEFT) { // Single left click redraw = 1; } // Output mouse position cout << "Mouse: " << windowEvent.button.x << " " << windowEvent.button.y << endl; } }// if(SDL_PollEvent(&windowEvent)) if (okAlt) { // Either ALT key if (k[SDL_SCANCODE_RETURN]) { // ALT + ENTER, toggle fullscreen // Consider matching current window resolution to closest preset array of valid full screen resolutions. fullscreen_toggle = 1; } if (k[SDL_SCANCODE_P]) { if (SDL_GetTicks() - key_cooldown_timer > key_cooldown_timer_max) { // Action cooldown timer is ready. Avoids ON / OFF flicker // Play Music if (!Mix_PlayingMusic()) { cout << "PLAY"; Mix_PlayMusic(bgm, -1); } else if (Mix_PausedMusic()) { cout << "RESUME"; Mix_ResumeMusic(); } else { cout << "PAUSE"; Mix_PauseMusic(); } key_cooldown_timer = SDL_GetTicks(); } }// SDL_SCANCODE_P if (k[SDL_SCANCODE_S]) { // Stop Music Mix_HaltMusic(); } }// okAlt //Handle window events fullscreen_toggle = window.handleEvent(windowEvent, renderTarget, fullscreen_toggle); // Player Update and IntersectsWith for (i = 0; i < players; i++) { player[i].Update(deltaTime, k); for (ii = 0; ii < players; ii++) { if(i != ii)// Not self player[i].IntersectsWith(player[ii]); } } // Camera cameraRect.x = player[0].GetOriginX() - window.getWidth() / 2; cameraRect.y = player[0].GetOriginY() - window.getHeight() / 2; // Normalize if (cameraRect.x < 0) cameraRect.x = 0; if (cameraRect.y < 0) cameraRect.y = 0; if (cameraRect.x + cameraRect.w >= bg_texture_w) cameraRect.x = bg_texture_w - window.getWidth(); if (cameraRect.y + cameraRect.h >= bg_texture_h) cameraRect.y = bg_texture_h - window.getHeight(); redraw = 1; // Don't judge me if (redraw) { // Redraw should definatly pretty much be at the end of loop // Clear window SDL_RenderClear(renderTarget); // Copy camera from bg_texture SDL_RenderCopy(renderTarget, bg_texture, &cameraRect, NULL); // Draw players for (i = 0; i < players; i++) player[i].Draw(renderTarget, cameraRect); // Print text SDL_RenderCopy(renderTarget, text_texture, NULL, &textRect); // Show the rendered content SDL_RenderPresent(renderTarget); redraw = 0; }// if(redraw) }// while(true) // Free windows window.free(); SDL_DestroyTexture(bg_texture); SDL_DestroyTexture(spritesheet_texture); SDL_DestroyTexture(text_texture); TTF_CloseFont(font); // Free Renderers SDL_DestroyRenderer(renderTarget); // Free music Mix_FreeMusic(bgm); // Close systems Mix_Quit(); TTF_Quit(); IMG_Quit(); SDL_Quit(); return EXIT_SUCCESS; }// main() SDL_Texture *LoadTexture(string filepath, SDL_Renderer *renderTarget) { // Create texture SDL_Texture *texture = nullptr; // Load surface SDL_Surface *surface = IMG_Load(filepath.c_str()); if (surface == NULL) { // surface didn't load logSDLError("LoadTexture surface "); } else { SDL_SetColorKey(surface, SDL_TRUE, SDL_MapRGB(surface->format, 0, 0, 0)); texture = SDL_CreateTextureFromSurface(renderTarget, surface); //SDL_SetTextureColorMod(texture, 120, 150, 140); if (texture == NULL) logSDLError("LoadTexture texture "); } SDL_FreeSurface(surface); return texture; } void logSDLError(const string msg){ cout << msg << " Error: " << SDL_GetError() << endl; SDL_Delay(4000); } SDL_Rect sdlrect(int x, int y, int w, int h) { SDL_Rect rect = {x, y, w, h}; return rect; } SDL_Surface *OptimizedSurface(string filepath, SDL_Surface *windowSurface) { SDL_Surface *optimizedSurf = nullptr; SDL_Surface *surface = IMG_Load(filepath.c_str()); if (surface == NULL) { cout << "Error: " << endl; } else { optimizedSurf = SDL_ConvertSurface(surface, windowSurface->format, 0); if (optimizedSurf == NULL) cout << "Error: " << endl; } SDL_FreeSurface(surface); return optimizedSurf; } Player.h
      #pragma once #include <iostream> #include "SDL.h" #include <String> #include "SDL_mixer.h" using namespace std; enum player_control { ePlayer_control_up, ePlayer_control_down, ePlayer_control_left, ePlayer_control_right, ePlayer_control_type_minus, ePlayer_control_type_plus }; class Player { private: SDL_Rect cropRect; SDL_Texture *texture; int spritesheet_texture_w, spritesheet_texture_h;//size of spritesheet texture bool isActive;//animation timer SDL_Scancode keys[6]; int frame_w, frame_h;//16, 16 float frameTimerMax; float frameTimer;//0..frameTimerMax int frame;//0..1 int frameMax;//2 int way;//0..3 int classType;//0..53 float moveSpeed; float cast_cooldown_max; Mix_Chunk *soundEffect; int originX, originY; int radius; Uint32 key_cooldown_timer; string name; public: void Player_new(SDL_Texture *spritesheet_texture, int x, int y); Player(); ~Player(); void Update(float delta, const Uint8 *keyState); void Draw(SDL_Renderer *renderTarget, SDL_Rect cameraRect); bool IntersectsWith(Player &p); int GetOriginX(); int GetOriginY(); int GetRadius(); SDL_Rect positionRect; }; Player.cpp
      #pragma once #include "Player.h" #include "SDL_image.h" #include "SDL_mixer.h" #include <iostream> #include <String> #include <cmath> using namespace std; Player::Player() { cropRect = {0, 0, 16, 16}; texture = nullptr; spritesheet_texture_w = spritesheet_texture_h = 0;//size of spritesheet texture isActive = false;//animation timer keys[6]; frame_w = frame_h = 16;//16, 16 frameTimerMax = 0.5f; frameTimer = 0;//0..frameTimerMax frame = 0;//0..1 frameMax = 2;//2 way = 0;//0..3 classType = 0;//0..53 moveSpeed = 200.0f; radius = frame_w / 2; soundEffect = nullptr; key_cooldown_timer = 0; cast_cooldown_max = 190.0f; static int playerNumber = 0; playerNumber++; name = "Player:" + to_string(playerNumber); // Setup keys for player 1 // ** I see the enum didn't exist when this was written ** if (playerNumber == 1) { keys[0] = SDL_SCANCODE_W; keys[1] = SDL_SCANCODE_S; keys[2] = SDL_SCANCODE_A; keys[3] = SDL_SCANCODE_D; keys[4] = SDL_SCANCODE_KP_MINUS; keys[5] = SDL_SCANCODE_KP_PLUS; } else { // Setup keys all other players (not 1) keys[0] = SDL_SCANCODE_UP; keys[1] = SDL_SCANCODE_DOWN; keys[2] = SDL_SCANCODE_LEFT; keys[3] = SDL_SCANCODE_RIGHT; keys[4] = SDL_SCANCODE_KP_DIVIDE; keys[5] = SDL_SCANCODE_KP_MULTIPLY; } }//Player::Player() void Player::Player_new(SDL_Texture *spritesheet_texture, int x, int y) { // This is new player isActive = false; // Read size of spritesheet texture SDL_QueryTexture(spritesheet_texture, NULL, NULL, &spritesheet_texture_w, &spritesheet_texture_h); texture = spritesheet_texture; // spritesheet rect cropRect = { 0, 0, 16, 16 }; // player screen position positionRect = { x, y, 16, 16 }; // Defaults moveSpeed = 200.0f; radius = frame_w / 2; frameTimer = 0; frame = 0; frameMax = 2; way = 0; classType = 0; originX = frame_w / 2; originY = frame_h / 2; soundEffect = Mix_LoadWAV("../../Sounds/whipcrack1.wav"); cout << "Name: " << name << endl; }//Player::Player_new() void Player::Update(float delta, const Uint8 *keyState) { isActive = true; if (keyState[keys[ePlayer_control_up]]) { way = 0; positionRect.y -= moveSpeed * delta; cropRect.x = (way * cropRect.w * frameMax) + (frame * cropRect.w); } if (keyState[keys[ePlayer_control_down]]) { way = 1; positionRect.y += moveSpeed * delta; cropRect.x = (way * cropRect.w * frameMax) + (frame * cropRect.w); } if (keyState[keys[ePlayer_control_left]]) { way = 3; positionRect.x -= moveSpeed * delta; cropRect.x = (way * cropRect.w * frameMax) + (frame * cropRect.w); } if (keyState[keys[ePlayer_control_right]]) { way = 2; positionRect.x += moveSpeed * delta; cropRect.x = (way * cropRect.w * frameMax) + (frame * cropRect.w); } if (keyState[keys[ePlayer_control_type_minus]]) { if (SDL_GetTicks() - key_cooldown_timer > cast_cooldown_max) { key_cooldown_timer = SDL_GetTicks(); Mix_PlayChannel(-1, soundEffect, 0); classType--; if (classType < 0) classType = spritesheet_texture_h / cropRect.h - 1; cropRect.y = classType * cropRect.h; } } if (keyState[keys[ePlayer_control_type_plus]]) { if (SDL_GetTicks() - key_cooldown_timer > cast_cooldown_max) { key_cooldown_timer = SDL_GetTicks(); Mix_PlayChannel(-1, soundEffect, 0); classType++; if (classType >= spritesheet_texture_h / cropRect.h) classType = 0; cropRect.y = classType * cropRect.h; } } if (isActive) { frameTimer += delta; if (frameTimer >= frameTimerMax){ frameTimer = 0; cropRect.x = (way * cropRect.w * frameMax) + (frame * cropRect.w); if (frame >= frameMax - 1) frame = 0; else frame++; } } else { frameTimer = 0; } }//Player::Update() void Player::Draw(SDL_Renderer *renderTarget, SDL_Rect cameraRect) { SDL_Rect drawingRect = { positionRect.x - cameraRect.x, positionRect.y - cameraRect.y, positionRect.w, positionRect.h }; SDL_RenderCopy(renderTarget, texture, &cropRect, &drawingRect); } bool Player::IntersectsWith(Player &p){ if (sqrt(pow(GetOriginX() - p.GetOriginX(), 2) + pow(GetOriginY() - p.GetOriginY(), 2)) >= radius + p.GetRadius()) { SDL_SetTextureColorMod(texture, 255, 255, 255); return false; } SDL_SetTextureColorMod(texture, 255, 0, 0); return true; } Player::~Player() { SDL_DestroyTexture(texture); Mix_FreeChunk(soundEffect); } int Player::GetOriginX() { return positionRect.x + originX; } int Player::GetOriginY() { return positionRect.y + originY; } int Player::GetRadius() { return radius; }  
×
×
  • Create New...