Release 0.1.10-alpha: Merge branch 'dev'

master
krzys-h 2017-05-24 14:34:19 +02:00
commit 1dcc70c097
142 changed files with 4891 additions and 2421 deletions

View File

@ -16,9 +16,9 @@ set(COLOBOT_VERSION_MINOR 1)
set(COLOBOT_VERSION_REVISION 9)
# Used on official releases
set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha")
#set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha")
# Used on unreleased, development builds
#set(COLOBOT_VERSION_UNRELEASED "+alpha")
set(COLOBOT_VERSION_UNRELEASED "+alpha")
# Append git characteristics to version
if(DEFINED COLOBOT_VERSION_UNRELEASED)
@ -132,8 +132,8 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
message(STATUS "Detected GCC version 4.7+")
set(NORMAL_CXX_FLAGS "-std=gnu++11 -Wall -Wold-style-cast -pedantic-errors")
set(NORMAL_CXX_FLAGS "${NORMAL_CXX_FLAGS} -fno-delete-null-pointer-checks") # Temporary hack, see #828
set(NORMAL_CXX_FLAGS "-std=gnu++11 -Wall -Werror -Wold-style-cast -pedantic-errors")
set(NORMAL_CXX_FLAGS "${NORMAL_CXX_FLAGS} -Wno-error=deprecated-declarations") # updated version of physfs is not available on some platforms so we keep using deprecated functions, see #958
set(RELEASE_CXX_FLAGS "-O2")
set(DEBUG_CXX_FLAGS "-g -O0")
set(TEST_CXX_FLAGS "-pthread")
@ -145,7 +145,8 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
message(STATUS "Detected Clang version 3.1+")
set(NORMAL_CXX_FLAGS "-std=c++11 -Wall -Wold-style-cast -pedantic-errors")
set(NORMAL_CXX_FLAGS "-std=c++11 -Wall -Werror -Wold-style-cast -pedantic-errors")
set(NORMAL_CXX_FLAGS "${NORMAL_CXX_FLAGS} -Wno-error=deprecated-declarations") # updated version of physfs is not available on some platforms so we keep using deprecated functions, see #958
set(RELEASE_CXX_FLAGS "-O2")
set(DEBUG_CXX_FLAGS "-g -O0")
set(TEST_CXX_FLAGS "-pthread")

View File

@ -351,7 +351,7 @@ IDL_PROPERTY_SUPPORT = YES
# all members of a group must be documented explicitly.
# The default value is: NO.
DISTRIBUTE_GROUP_DOC = NO
DISTRIBUTE_GROUP_DOC = YES
# Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that
@ -993,7 +993,7 @@ USE_HTAGS = NO
# See also: Section \class.
# The default value is: YES.
VERBATIM_HEADERS = YES
VERBATIM_HEADERS = NO
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the

31
Jenkinsfile vendored
View File

@ -1,8 +1,16 @@
node('master') {
stage 'Pull changes'
checkout scm
#!/usr/bin/env groovy
if (env.BRANCH_NAME.startsWith('PR-')) {
properties([[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', artifactNumToKeepStr: '1']]])
} else {
properties([[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', artifactDaysToKeepStr: '30', artifactNumToKeepStr: '20']]])
}
stage 'Build Windows'
node('master') {
stage('Pull changes') {
checkout scm
}
stage('Build Windows') {
sh 'mkdir -p build/windows'
dir('build/windows') {
sh '''
@ -17,8 +25,9 @@ node('master') {
}
sh 'rm -f windows-debug.zip'
zip zipFile: 'windows-debug.zip', archive: true, dir: 'build/windows/install'
}
stage 'Build Linux'
stage('Build Linux') {
sh 'mkdir -p build/linux'
dir('build/linux') {
sh '''
@ -34,17 +43,25 @@ node('master') {
}
sh 'rm -f linux-debug.zip'
zip zipFile: 'linux-debug.zip', archive: true, dir: 'build/linux/install'
}
stage 'Doxygen'
stage('Doxygen') {
dir('build/linux') {
sh 'make doc'
}
publishHTML target: [$class: 'HtmlPublisherTarget', reportName: 'Doxygen', reportDir: 'build/linux/doc/html', reportFiles: 'index.html']
}
stage 'Run tests'
stage('Run tests') {
dir('build/linux') {
sh './colobot_ut --gtest_output=xml:gtestresults.xml || true'
}
step([$class: 'XUnitBuilder', testTimeMargin: '3000', thresholdMode: 1, thresholds: [[$class: 'FailedThreshold', failureNewThreshold: '', failureThreshold: '', unstableNewThreshold: '', unstableThreshold: '0'], [$class: 'SkippedThreshold', failureNewThreshold: '', failureThreshold: '', unstableNewThreshold: '', unstableThreshold: '']], tools: [[$class: 'GoogleTestType', deleteOutputFiles: true, failIfNotNew: true, pattern: 'build/linux/gtestresults.xml', skipNoTestFiles: false, stopProcessingIfError: true]]])
}
// Clean workspace after building pull requests
// to save disk space on the Jenkins host
if (env.BRANCH_NAME.startsWith('PR-')) {
cleanWs()
}
}

View File

@ -6,7 +6,7 @@ This is official repository for the open-source Colobot: Gold Edition project de
The source code contained here was released by Epsitec -- the original creator of the game -- on open source (GPLv3) license. The code was given and the rights granted specifically to ICC community in March 2012. Since then, we have been developing the game further.
More information for developers (in English) can be found on the [developer wiki](http://colobot.info/wiki/dev/) or [our forum](http://colobot.info/forum/). However, the freshest source of information is our IRC channels (see below).
More information for developers (in English) can be found on [our forum](http://colobot.info/forum/). However, the freshest source of information is our IRC channels (see below).
This repository contains only the source code of the project. The game requires also data files which are now provided as git submodule and are hosted in [separate repository](https://github.com/colobot/colobot-data).

2
data

@ -1 +1 @@
Subproject commit f96cf394a327210ac9e40d68d68963f25633f758
Subproject commit 2794fd57c32412d4c9103d20c1ec0c888e1e97a0

View File

@ -260,6 +260,19 @@ msgstr ""
msgid "Generating"
msgstr ""
msgid "Results"
msgstr ""
msgid "The battle has ended"
msgstr ""
#, c-format
msgid "%s: %d pts"
msgstr ""
msgid "Code battle"
msgstr ""
msgid "Cancel"
msgstr ""
@ -1346,6 +1359,9 @@ msgstr ""
msgid "Unknown command"
msgstr ""
msgid "This object is currently busy"
msgstr ""
msgid "Impossible when flying"
msgstr ""
@ -1598,6 +1614,18 @@ msgstr ""
msgid "Press \\key help; to read instructions on your SatCom"
msgstr ""
#, c-format
msgid "<<< Team %s finished! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s lost! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s recieved %d points >>>"
msgstr ""
msgid "Opening bracket missing"
msgstr ""
@ -1733,6 +1761,18 @@ msgstr ""
msgid "Ambiguous call to overloaded function"
msgstr ""
msgid "Function needs return type \"void\""
msgstr ""
msgid "Class name expected"
msgstr ""
msgid "Non-void function needs \"return;\""
msgstr ""
msgid "This parameter needs a default value"
msgstr ""
msgid "Dividing by zero"
msgstr ""

286
po/de.po
View File

@ -1,21 +1,21 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
# Chris <marius.romanus@gmx.net>, 2016.
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: DATE\n"
"PO-Revision-Date: 2014-07-28 09:27+0200\n"
"Last-Translator: krzys_h <krzys_h@interia.pl>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"PO-Revision-Date: 2016-10-28 21:29+0200\n"
"Last-Translator: Chris <marius.romanus@gmx.net>\n"
"Language-Team: Colobot: Gold Edition freelancer\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Pootle 2.5.1.1\n"
"X-Generator: Virtaal 0.7.1\n"
"X-Language: de_DE\n"
"X-Source-Language: en_US\n"
"X-POOTLE-MTIME: 1406536037.000000\n"
@ -29,6 +29,10 @@ msgstr "Es fehlt eine offene eckige Klammer \" [ \""
msgid "\" ] \" missing"
msgstr "Es fehlt eine geschlossene eckige Klammer \" ] \""
#, c-format
msgid "%s: %d pts"
msgstr ""
msgid "..behind"
msgstr "..hinten"
@ -42,7 +46,7 @@ msgid "1) First click on the key you want to redefine."
msgstr "1) Klicken Sie auf die neu zu definierende Taste."
msgid "2) Then press the key you want to use instead."
msgstr "2) Drücken Sie auf die neue Taste."
msgstr "2) Drücken Sie auf die neu zu verwendende Taste."
msgid "<< Back \\Back to the previous screen"
msgstr "<< Zurück \\Zurück zum Hauptmenü"
@ -50,6 +54,18 @@ msgstr "<< Zurück \\Zurück zum Hauptmenü"
msgid "<<< Sorry; mission failed >>>"
msgstr "<<< Mission gescheitert >>>"
#, c-format
msgid "<<< Team %s finished! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s lost! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s recieved %d points >>>"
msgstr ""
msgid "<<< Well done; mission accomplished >>>"
msgstr "<<< Bravo, Mission vollendet >>>"
@ -57,7 +73,7 @@ msgid "A label must be followed by \"for\"; \"while\"; \"do\" or \"switch\""
msgstr "Ein Label kann nur vor den Anweisungen \"for\", \"while\", \"do\" oder \"switch\" vorkommen"
msgid "A variable can not be declared twice"
msgstr "Eine Variable wird zum zweiten Mal deklariert"
msgstr "Eine Variable darf nicht zwei Mal deklariert werden"
msgid "Abort\\Abort the current mission"
msgstr "Abbrechen\\Mission abbrechen"
@ -72,7 +88,7 @@ msgid "Access to solutions\\Show program \"4: Solution\" in the exercises"
msgstr "Lösung zugänglich\\Die Lösung ist im Programmslot \"4: Lösung\" zugänglich"
msgid "Add new program"
msgstr ""
msgstr "Neues Programm hinzufügen"
msgid "Alien Queen"
msgstr "Insektenkönigin"
@ -85,6 +101,8 @@ msgstr "Trägt schon etwas"
msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)"
msgstr ""
"Alternativer Kameramodus\\Seitwärts bewegen statt rotieren (bei freier "
"Kamera)"
msgid "Ambiguous call to overloaded function"
msgstr ""
@ -99,7 +117,7 @@ msgid "Analyzes only organic matter"
msgstr "Analysiert nur Orgastoff"
msgid "Anisotropy level\\Anisotropy level"
msgstr ""
msgstr "Anisotropie-Level\\Anisotropie-Level"
msgid "Ant"
msgstr "Ameise"
@ -111,7 +129,7 @@ msgid "Appearance\\Choose your appearance"
msgstr "Aussehen\\Erscheinungsbild des Astronauten einstellen"
msgid "Apply changes\\Activates the changed settings"
msgstr "Änderungen ausführen\\Getätigte Einstellungen ausführen"
msgstr "Änderungen anwenden\\Getätigte Einstellungen anwenden"
msgid "Appropriate constructor missing"
msgstr "Es gibt keinen geeigneten Konstruktor"
@ -127,19 +145,22 @@ msgstr "Automatisches Einrücken\\Beim Bearbeiten der Programme"
msgid "Autosave interval\\How often your game will autosave"
msgstr ""
"Auto-Speichern Zeitintervall\\Wie oft das Spiel automatisch abgespeichert "
"wird"
msgid "Autosave slots\\How many autosave slots you'll have"
msgstr ""
"Auto-Speicherplätze\\Wie viele Plätze zum automatischen Speichern zur "
"Verfügung stehen"
msgid "Autosave\\Enables autosave"
msgstr ""
msgstr "Auto-Speichern\\Aktiviert die automatische Speicherung"
msgid "Back"
msgstr "Vorherg. Seite"
#, fuzzy
msgid "Background sound:\\Volume of audio tracks"
msgstr "Geräuschkulisse:\\Lautstärke der Soundtracks der CD"
msgstr "Hintergrundgeräusche:\\Lautstärke der Soundtracks"
msgid "Backward (\\key down;)"
msgstr "Rückwärts (\\key down;)"
@ -157,7 +178,7 @@ msgid "Black box"
msgstr "Flugschreiber"
msgid "Blood\\Display blood when the astronaut is hit"
msgstr ""
msgstr "Blut\\Blut anzeigen, wenn der Astronaut verletzt wird"
msgid "Blue"
msgstr "Blau"
@ -294,28 +315,25 @@ msgstr "Kamera (\\key camera;)"
msgid "Camera back\\Moves the camera backward"
msgstr "Kamera weiter\\Bewegung der Kamera rückwärts"
#, fuzzy
msgid "Camera border scrolling\\Scrolling when the mouse touches right or left border"
msgstr "Kameradrehung mit der Maus\\Die Kamera dreht wenn die Maus den Rand erreicht"
msgstr ""
"Kamerabewegung am Bildschirmrand\\Die Kamera dreht wenn die Maus den rechten "
"oder linken Rand erreicht"
msgid "Camera closer\\Moves the camera forward"
msgstr "Kamera näher\\Bewegung der Kamera vorwärts"
#, fuzzy
msgid "Camera down\\Turns the camera down"
msgstr "Kamera näher\\Bewegung der Kamera vorwärts"
msgstr "Kamera ab\\Bewegt die Kamera abwärts"
#, fuzzy
msgid "Camera left\\Turns the camera left"
msgstr "Kamera näher\\Bewegung der Kamera vorwärts"
msgstr "Kamera links\\Schwenkt die Kamera nach links"
#, fuzzy
msgid "Camera right\\Turns the camera right"
msgstr "Drehung nach rechts\\Steuer rechts"
msgstr "Kamera rechts\\Schwenkt die Kamera nach rechts"
#, fuzzy
msgid "Camera up\\Turns the camera up"
msgstr "Kamera (\\key camera;)"
msgstr "Kamera auf\\Bewegt die Kamera aufwärts"
msgid "Can not produce not researched object"
msgstr "Das erforschte Objekt kann nicht produziert werden"
@ -333,13 +351,13 @@ msgid "Cancel\\Cancel all changes"
msgstr "Abbrechen\\Editor schließen"
msgid "Challenges"
msgstr "Challenges"
msgstr "Herausforderungen"
msgid "Challenges in the chapter:"
msgstr "Liste der Challenges des Kapitels:"
msgstr "Herausforderungen in diesem Kapitel:"
msgid "Challenges\\Programming challenges"
msgstr "Challenges\\Herausforderungen"
msgstr "Herausforderungen\\Programmieraufgaben"
msgid "Change camera\\Switches between onboard camera and following camera"
msgstr "Andere Kamera\\Sichtpunkt einstellen"
@ -351,20 +369,22 @@ msgid "Chapters:"
msgstr "Liste der Kapitel:"
msgid "Cheat console\\Show cheat console"
msgstr ""
msgstr "Mogel-Konsole\\Zeige die Mogel-Konsole"
msgid "Checkpoint"
msgstr "Checkpoint"
msgstr "Kontrollstelle"
msgid "Class name expected"
msgstr ""
msgid "Climb\\Increases the power of the jet"
msgstr "Steigen\\Leistung des Triebwerks steigern"
msgid "Clone program"
msgstr ""
msgstr "Programm duplizieren"
#, fuzzy
msgid "Clone selected program"
msgstr "Gewähltes Programm bearbeiten"
msgstr "Gewähltes Programm duplizieren"
msgid "Close"
msgstr "Schließen"
@ -372,11 +392,14 @@ msgstr "Schließen"
msgid "Closing bracket missing"
msgstr "Es fehlt eine geschlossene Klammer \")\""
msgid "Code battles"
msgid "Code battle"
msgstr ""
msgid "Code battles"
msgstr "Programmierschlacht"
msgid "Code battles\\Program your robot to be the best of them all!"
msgstr ""
msgstr "Programmierschlacht\\Schreibe das Programm für den besten Roboter!"
msgid "Colobot rules!"
msgstr "Colobot ist wunderbar!"
@ -385,7 +408,7 @@ msgid "Colobot: Gold Edition"
msgstr "Colobot: Gold Edition"
msgid "Command line"
msgstr "Befehleingabe"
msgstr "Befehlseingabe"
msgid "Compilation ok (0 errors)"
msgstr "Kompilieren OK (0 Fehler)"
@ -403,7 +426,7 @@ msgid "Controls\\Keyboard, joystick and mouse settings"
msgstr "Steuerung\\Auswahl der Tasten"
msgid "Converts ore to titanium"
msgstr "Konverter Erz-Titan"
msgstr "Konvertiert Erz in Titan"
msgid "Copy"
msgstr "Kopieren"
@ -414,12 +437,11 @@ msgstr "Kopieren (Ctrl+C)"
msgid "Current mission saved"
msgstr "Mission gespeichert"
#, fuzzy
msgid "Custom levels:"
msgstr "Userlevels:"
msgstr "Benutzerdefinierte Level:"
msgid "Custom levels\\Levels from mods created by the users"
msgstr ""
msgstr "Benutzerdefinierte Level\\Level die von anderen Spieler erstellt wurden"
msgid "Customize your appearance"
msgstr "Aussehen einstellen"
@ -430,9 +452,8 @@ msgstr "Ausschneiden (Ctrl+X)"
msgid "Defense tower"
msgstr "Geschützturm"
#, fuzzy
msgid "Delete mark"
msgstr "Zerstören"
msgstr "Markierung entfernen"
msgid "Delete player\\Deletes the player from the list"
msgstr "Spieler löschen\\Löscht den Spieler aus der Liste"
@ -459,7 +480,7 @@ msgid "Device\\Driver and resolution settings"
msgstr "Bildschirm\\Driver und Bildschirmauflösung"
msgid "Dividing by zero"
msgstr "Teilung durch Null"
msgstr "Division durch Null"
msgid "Do you really want to destroy the selected building?"
msgstr "Wollen Sie das angewählte Gebäude wirklich zerstören ?"
@ -484,10 +505,10 @@ msgid "Dynamic lighting\\Mobile light sources"
msgstr "Dynamische Beleuchtung\\Dynamische Beleuchtung"
msgid "Dynamic shadows ++\\Dynamic shadows + self shadowing"
msgstr ""
msgstr "Dynamische Schatten ++\\Dynamische Schatten + Eigenschatten"
msgid "Dynamic shadows\\Beautiful shadows!"
msgstr ""
msgstr "Dynamische Schatten\\Hübsche Schatten!"
msgid "Edit the selected program"
msgstr "Gewähltes Programm bearbeiten"
@ -529,7 +550,7 @@ msgid "Explosive"
msgstr "Sprengstoff"
msgid "Expression expected after ="
msgstr ""
msgstr "Nach = wird ein Ausdruck erwartet"
msgid "Extend shield (\\key action;)"
msgstr "Schutzschild ausfahren (\\key action;)"
@ -556,7 +577,7 @@ msgid "Fixed mine"
msgstr "Landmine"
msgid "Flat ground not large enough"
msgstr "Ebener Boden nicht groß genug"
msgstr "Ebene Fläche nicht groß genug"
msgid "Fog\\Fog"
msgstr "Nebel\\Nebelschwaden"
@ -569,7 +590,7 @@ msgid "Folder: %s"
msgstr "Ordner: %s"
msgid "Font size"
msgstr "Zeichengröße"
msgstr "Schriftgröße"
msgid "Forward"
msgstr "Nächste Seite"
@ -599,13 +620,13 @@ msgid "Found key D (site for derrick)"
msgstr "Markierung für vergrabenen Schlüssel D"
msgid "Free game"
msgstr "Freestyle"
msgstr "Freies Spiel"
msgid "Free game on this planet:"
msgstr "Liste der freien Levels des Planeten:"
msgid "Free game\\Free game without a specific goal"
msgstr "Freestyle\\Freies Spielen ohne vorgegebenes Ziel"
msgstr "Freies Spiel\\Freies Spielen ohne vorgegebenes Ziel"
msgid "Full screen\\Full screen or window mode"
msgstr "Vollbildschirm\\Vollbildschirm oder Fenster"
@ -616,6 +637,9 @@ msgstr "Diese Funktion gibt es schon"
msgid "Function name missing"
msgstr "Hier muss der Name der Funktion stehen"
msgid "Function needs return type \"void\""
msgstr ""
msgid "Game speed"
msgstr "Spielgeschwindigkeit"
@ -626,10 +650,10 @@ msgid "Gantry crane"
msgstr "Träger"
msgid "Generating"
msgstr ""
msgstr "Generieren"
msgid "Gold Edition development by:"
msgstr "Goldausgabe Entwicklung von:"
msgstr "Gold-Edition entwickelt von:"
msgid "Goto: destination occupied"
msgstr "Ziel ist schon besetzt"
@ -641,7 +665,7 @@ msgid "Grab or drop (\\key action;)"
msgstr "Nehmen oder hinlegen (\\key action;)"
msgid "Graphics\\Graphics settings"
msgstr "Grafik\\Grafische Einstellungen"
msgstr "Grafik\\Grafik-Einstellungen"
msgid "Green"
msgstr "Grün"
@ -662,7 +686,7 @@ msgid "Help about selected object"
msgstr "Anweisungen über das ausgewählte Objekt"
msgid "Help balloons\\Explain the function of the buttons"
msgstr "Hilfsblasen\\Hilfsblasen"
msgstr "Hilfeblasen\\Hilfeblasen"
msgid "Highest\\Highest graphic quality (lowest frame rate)"
msgstr "Max.\\Beste Qualität (niedriges Framerate)"
@ -697,9 +721,8 @@ msgstr "Roboter ungeeignet"
msgid "Inappropriate cell type"
msgstr "Falscher Batterietyp"
#, fuzzy
msgid "Inappropriate object"
msgstr "Roboter ungeeignet"
msgstr "Objekt ungeeignet"
msgid "Incorrect index type"
msgstr "Falscher Typ für einen Index"
@ -738,10 +761,10 @@ msgid "Instructions\\Shows the instructions for the current mission"
msgstr "Anweisungen\\Anweisungen für die Mission oder Übung"
msgid "Internal error - tell the developers"
msgstr "Interner Fehler - Benachrichtige die Entwickler"
msgstr "Interner Fehler - Benachrichtige bitte die Entwickler"
msgid "Invert\\Invert values on this axis"
msgstr ""
msgstr "Invertieren\\Die Werte dieser Achse invertieren"
msgid "Jet temperature"
msgstr "Triebwerktemperatur"
@ -801,39 +824,37 @@ msgid "Load\\Loads the selected mission"
msgstr "Laden\\Öffnet eine gespeicherte Mission"
msgid "Loading basic level settings"
msgstr ""
msgstr "Lade Level-Grundeinstellungen"
#, fuzzy
msgid "Loading finished!"
msgstr "Programm beendet"
msgstr "Laden beendet!"
msgid "Loading music"
msgstr ""
msgstr "Lade Musik"
#, fuzzy
msgid "Loading objects"
msgstr "Liste der Objekte"
msgstr "Lade Objekte"
msgid "Loading terrain"
msgstr ""
msgstr "Lade Gelände"
msgid "Lowest\\Minimum graphic quality (highest frame rate)"
msgstr "Min.\\Minimale Qualität (großes Framerate)"
msgid "Lunar Roving Vehicle"
msgstr "Lunar Roving Vehicle"
msgstr "Mondlandefahrzeug"
msgid "MSAA\\Multisample anti-aliasing"
msgstr ""
msgstr "MSAA\\Multisample anti-aliasing"
msgid "Maximize"
msgstr "Großes Fenster"
msgid "Minimize"
msgstr "Reduzieren"
msgstr "Verkleinern"
msgid "Mipmap level\\Mipmap level"
msgstr ""
msgstr "Mipmap-Level\\Mipmap-Level"
msgid "Mission name"
msgstr "Name der Mission"
@ -853,13 +874,11 @@ msgstr "Umkehr X\\Umkehr der Kameradrehung X-Achse"
msgid "Mouse inversion Y\\Inversion of the scrolling direction on the Y axis"
msgstr "Umkehr Y\\Umkehr der Kameradrehung Y-Achse"
#, fuzzy
msgid "Move selected program down"
msgstr "Gewähltes Programm bearbeiten"
msgstr "Gewähltes Programm nach unten"
#, fuzzy
msgid "Move selected program up"
msgstr "Gewähltes Programm bearbeiten"
msgstr "Gewähltes Programm nach oben"
msgid "Mute\\No sound"
msgstr "Kein Ton\\Keine Geräusche und Geräuschkulisse"
@ -889,7 +908,7 @@ msgid "Next object\\Selects the next object"
msgstr "Nächstes auswählen\\Nächstes Objekt auswählen"
msgid "No"
msgstr ""
msgstr "Nein"
msgid "No energy in the subsoil"
msgstr "Kein unterirdisches Energievorkommen"
@ -901,10 +920,10 @@ msgid "No function running"
msgstr "Keine Funktion wird ausgeführt"
msgid "No function with this name accepts this kind of parameter"
msgstr "Keine Funktion mit diesem Namen verträgt Parameter diesen Typs"
msgstr "Keine Funktion mit diesem Namen akzeptiert Parameter diesen Typs"
msgid "No function with this name accepts this number of parameters"
msgstr "Keine Funktion mit diesem Namen verträgt diese Anzahl Parameter"
msgstr "Keine Funktion mit diesem Namen akzeptiert diese Anzahl Parameter"
msgid "No information exchange post within range"
msgstr "Kein Infoserver in Reichweite"
@ -934,6 +953,9 @@ msgid "No uranium to transform"
msgstr "Kein konvertierbares Platin"
msgid "No userlevels installed!"
msgstr "Keine benutzerdefinierten Level vorhanden"
msgid "Non-void function needs \"return;\""
msgstr ""
msgid "Normal size"
@ -1012,7 +1034,7 @@ msgid "Opening bracket missing"
msgstr "Es fehlt eine offene Klammer \"(\""
msgid "Operation impossible with value \"nan\""
msgstr "Operation mit dem Wert \"nan\""
msgstr "Operation mit dem Wert \"nan\" nicht möglich"
msgid "Options"
msgstr "Einstellungen"
@ -1039,16 +1061,18 @@ msgid "Paste (Ctrl+V)"
msgstr "Einfügen (Ctrl+V)"
msgid "Pause blur\\Blur the background on the pause screen"
msgstr ""
msgstr "Pausen-Unschärfe\\Während der Pause den Hintergrund unscharf zeichnen"
msgid "Pause in background\\Pause the game when the window is unfocused"
msgstr ""
"Pausieren im Hintergrund\\Spiel anhalten,enn das Spielfenster im Hintergrund "
"ist"
msgid "Pause/continue"
msgstr "Pause/Weitermachen"
msgid "Pause\\Pause the game without opening menu"
msgstr ""
msgstr "Pause\\Spiel pausieren, ohne das Menü zu öffnen"
msgid "Phazer shooter"
msgstr "Phazershooter"
@ -1093,10 +1117,10 @@ msgid "Player"
msgstr "Spieler"
msgid "Player name"
msgstr "Name "
msgstr "Spielername "
msgid "Player's name"
msgstr "Name "
msgstr "Name des Spielers"
msgid "Power cell"
msgstr "Elektrolytische Batterie"
@ -1117,7 +1141,7 @@ msgid "Press \\key help; to read instructions on your SatCom"
msgstr "Beziehen Sie sich auf Ihren SatCom, indem Sie auf \\key help; drücken"
msgid "Previous"
msgstr "Vorherg"
msgstr "Vorherg."
msgid "Previous object\\Selects the previous object"
msgstr "Vorherg. Auswahl\\Das vorhergehende Objekt auswählen"
@ -1132,11 +1156,10 @@ msgid "Private\\Private folder"
msgstr "Privat\\Privater Ordner"
msgid "Processing level file"
msgstr ""
msgstr "Verarbeite Level-Datei"
#, fuzzy
msgid "Program cloned"
msgstr "Programm beendet"
msgstr "Programm dupliziert"
msgid "Program editor"
msgstr "Programmeditor"
@ -1172,7 +1195,7 @@ msgid "Quake at explosions\\The screen shakes at explosions"
msgstr "Beben bei Explosionen\\Die Kamera bebt bei Explosionen"
msgid "Quit\\Quit Colobot: Gold Edition"
msgstr ""
msgstr "Beenden\\Colobot: Gold Edition schließen"
msgid "Quit\\Quit the current mission or exercise"
msgstr "Mission verlassen\\Eine Mission oder Übung verlassen"
@ -1207,11 +1230,9 @@ msgstr "Überreste einer Apollo-Mission"
msgid "Remove a flag"
msgstr "Sammelt die Fahne ein"
#, fuzzy
msgid "Remove selected program"
msgstr "Gewähltes Programm bearbeiten"
msgstr "Gewähltes Programm entfernen"
#, fuzzy
msgid "Render distance\\Maximum visibility"
msgstr "Sichtweite\\Maximale Sichtweite"
@ -1227,9 +1248,8 @@ msgstr "Forschungsprogramm schon ausgeführt"
msgid "Research program completed"
msgstr "Forschungsprogramm abgeschlossen"
#, fuzzy
msgid "Reserved keyword of CBOT language"
msgstr "Dieses Wort ist reserviert"
msgstr "Reserviertes Schlüsselwort in der CBOT Sprache"
msgid "Resolution"
msgstr "Auflösung"
@ -1238,15 +1258,18 @@ msgid "Resolution:"
msgstr "Auflösung:"
msgid "Resources"
msgstr ""
msgstr "Ressourcen"
msgid "Restart\\Restart the mission from the beginning"
msgstr "Neu anfangen\\Die Mission von vorne anfangen"
msgid "Restoring CBot execution state"
msgstr ""
msgstr "CBOT Ausführungsstatus wiederherstellen"
msgid "Restoring saved objects"
msgstr "Gespeicherte Objekte wiederherstellen"
msgid "Results"
msgstr ""
msgid "Return to start"
@ -1316,10 +1339,10 @@ msgid "Semicolon terminator missing"
msgstr "Es fehlt ein Strichpunkt \";\" am Ende der Anweisung"
msgid "Shadow resolution\\Higher means better range and quality, but slower"
msgstr ""
msgstr "Schatten-Auflösung\\Höher heißt bessere Qualität, aber langsamer"
msgid "Shield level"
msgstr "Schäden"
msgstr "Schildstärke"
msgid "Shield radius"
msgstr "Reichweite Schutzschild"
@ -1345,9 +1368,8 @@ msgstr "Zeigt die Lösung"
msgid "Sign \" : \" missing"
msgstr "Es fehlt ein Doppelpunkt \" : \""
#, fuzzy
msgid "Simple shadows\\Shadows spots on the ground"
msgstr "Schatten\\Schlagschatten auf dem Boden"
msgstr "Einfacher Schatten\\Schlagschatten auf dem Boden"
msgid "Size 1"
msgstr "Größe 1"
@ -1380,11 +1402,10 @@ msgid "Spaceship"
msgstr "Raumschiff"
msgid "Spaceship ruin"
msgstr "Raumschiffruine"
msgstr "Raumschiffswrack"
#, fuzzy
msgid "Speed 0.5x\\Half speed"
msgstr "Geschwindigkeit 1.0x\\Normale Spielgeschwindigkeit"
msgstr "Geschwindigkeit 0.5x\\Halbe Spielgeschwindigkeit"
msgid "Speed 1.0x\\Normal speed"
msgstr "Geschwindigkeit 1.0x\\Normale Spielgeschwindigkeit"
@ -1395,17 +1416,14 @@ msgstr "Geschwindigkeit 1.5x\\Spielgeschwindigkeit anderthalb Mal schneller"
msgid "Speed 2.0x\\Double speed"
msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell"
#, fuzzy
msgid "Speed 3.0x\\Triple speed"
msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell"
msgstr "Geschwindigkeit 3.0x\\Dreifache Spielgeschwindigkeit"
#, fuzzy
msgid "Speed 4.0x\\Quadruple speed"
msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell"
msgstr "Geschwindigkeit 4.0x\\Vierfache Spielgeschwindigkeit"
#, fuzzy
msgid "Speed 6.0x\\Sextuple speed"
msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell"
msgstr "Geschwindigkeit 6.0x\\Sechsfache Spielgeschwindigkeit"
msgid "Spider"
msgstr "Spinne"
@ -1428,12 +1446,11 @@ msgstr "Standard\\Standardfarben einsetzen"
msgid "Start"
msgstr "Startfläche"
#, fuzzy
msgid "Starting..."
msgstr "Startfläche"
msgstr "Starte..."
msgid "Still working ..."
msgstr "Prozess im Gang ..."
msgstr "Verarbeitung ..."
msgid "String missing"
msgstr "Hier wird eine Zeichenkette erwartet"
@ -1469,12 +1486,15 @@ msgid "Target bot"
msgstr "Mobile Zielscheibe"
msgid "Terrain relief"
msgstr ""
msgstr "Geländestruktur"
msgid "Texture filtering\\Texture filtering"
msgstr ""
msgstr "Texturfilterung\\Texturfilterung"
msgid "Textures"
msgstr "Texturen"
msgid "The battle has ended"
msgstr ""
msgid "The expression must return a boolean value"
@ -1496,7 +1516,7 @@ msgid "This class does not exist"
msgstr "Diese Klasse existiert nicht"
msgid "This is example code that cannot be run directly"
msgstr ""
msgstr "Das ist ein Beispiel Programm, das nicht direkt ausgeführt werden kann"
msgid "This is not a member of this class"
msgstr "Dieses Element gibt es nicht in dieser Klasse"
@ -1506,13 +1526,21 @@ msgstr "Dieses Label existiert nicht"
msgid "This menu is for userlevels from mods, but you didn't install any"
msgstr ""
"Dieses Menü ist für nachinstallierte Benutzer-Level, aber Du hast keine "
"installiert"
msgid "This object is currently busy"
msgstr ""
msgid "This object is not a member of a class"
msgstr "Das Objekt ist nicht eine Instanz einer Klasse"
msgid "This program is read-only, clone it to edit"
msgid "This parameter needs a default value"
msgstr ""
msgid "This program is read-only, clone it to edit"
msgstr "Dieses Programm ist schreibgeschützt. Dupliziere es zum Bearbeiten"
msgid "Thump (\\key action;)"
msgstr "Stampfen (\\key action;)"
@ -1589,10 +1617,10 @@ msgid "Type declaration missing"
msgstr "Hier muss ein Variablentyp stehen"
msgid "Unable to control enemy objects"
msgstr ""
msgstr "Feindliches Objekt kann nicht gesteuert werden"
msgid "Undo (Ctrl+Z)"
msgstr "Widerrufen (Ctrl+Z)"
msgstr "Rückgängig (Ctrl+Z)"
msgid "Unit"
msgstr "Einheit"
@ -1691,7 +1719,7 @@ msgid "Yellow flag"
msgstr "Gelbe Fahne"
msgid "Yes"
msgstr ""
msgstr "Ja"
msgid "You can fly with the keys (\\key gup;) and (\\key gdown;)"
msgstr "Sie können jetzt mit den Tasten \\key gup; und \\key gdown; fliegen"
@ -1702,27 +1730,35 @@ msgstr "Sie können keinen radioaktiven Gegenstand tragen"
msgid "You can not carry an object under water"
msgstr "Sie können unter Wasser nichts tragen"
#, fuzzy, c-format
#, c-format
msgid "You cannot use \"%s\" in this exercise (used: %d)"
msgstr "In dieser Übung verboten"
msgstr "\"%s\" kann in dieser Übung nicht verwendet werden (benutzt: %d)"
msgid "You found a usable object"
msgstr "Sie haben ein brauchbares Objekt gefunden"
#, fuzzy, c-format
#, c-format
msgid "You have to use \"%1$s\" at least once in this exercise (used: %2$d)"
msgid_plural "You have to use \"%1$s\" at least %3$d times in this exercise (used: %2$d)"
msgstr[0] "In dieser Übung verboten"
msgstr[1] "In dieser Übung verboten"
msgstr[0] ""
"In dieser Übung \"%1$s\" muß mindestens einmal verwendet werden (benutzt: %"
"2$d)"
msgstr[1] ""
"In dieser Übung muß \"%1$s\" mindestes %3$d Mal verwendet werden (benutzt: %"
"2$d)"
#, fuzzy, c-format
#, c-format
msgid "You have to use \"%1$s\" at most once in this exercise (used: %2$d)"
msgid_plural "You have to use \"%1$s\" at most %3$d times in this exercise (used: %2$d)"
msgstr[0] "In dieser Übung verboten"
msgstr[1] "In dieser Übung verboten"
msgstr[0] ""
"In dieser Übung darf \"%1$s\" höchstens einmal verwendet werden (benutzt: %"
"2$d)"
msgstr[1] ""
"In dieser Übung darf \"%1$s\" höchstens %3$d Mal verwendet werden (benutzt: %"
"2$d)"
msgid "You must get on the spaceship to take off"
msgstr "Gehen Sie an Bord, bevor Sie abheben"
msgstr "Begib Dich an Bord, bevor Du abhebst"
msgid "Zoom mini-map"
msgstr "Zoom Minikarte"
@ -1773,7 +1809,7 @@ msgid "\\Red flags"
msgstr "\\Rote Fahne"
msgid "\\Return to Colobot: Gold Edition"
msgstr ""
msgstr "\\Zurück zu Colobot: Gold-Edition"
msgid "\\SatCom on standby"
msgstr "\\SatCom in Standby"

View File

@ -1,11 +1,12 @@
# Didier Raboud <odyx@debian.org>, 2012, 2015, 2016.
# Martin Quinson <mquinson@debian.org>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Colobot 0.1.6\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: DATE\n"
"PO-Revision-Date: 2016-03-25 15:01+0100\n"
"Last-Translator: Didier Raboud <odyx@debian.org>\n"
"PO-Revision-Date: 2016-12-02 15:31+0100\n"
"Last-Translator: Martin Quinson <mquinson@debian.org>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -24,6 +25,10 @@ msgstr "\" [ \" attendu"
msgid "\" ] \" missing"
msgstr "\" ] \" attendu"
#, c-format
msgid "%s: %d pts"
msgstr ""
msgid "..behind"
msgstr "..derrière"
@ -45,6 +50,18 @@ msgstr "<< Retour \\Retour au niveau précédent"
msgid "<<< Sorry; mission failed >>>"
msgstr "<<< Désolé; mission échouée >>>"
#, c-format
msgid "<<< Team %s finished! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s lost! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s recieved %d points >>>"
msgstr ""
msgid "<<< Well done; mission accomplished >>>"
msgstr "<<< Bravo; mission terminée >>>"
@ -79,10 +96,10 @@ msgid "Already carrying something"
msgstr "Porte déjà quelque chose"
msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)"
msgstr ""
msgstr "Mode caméra alternatif\\Déplacements latéraux au lieu des rotations (pour la caméra libre)"
msgid "Ambiguous call to overloaded function"
msgstr ""
msgstr "Appel ambigu à une fonction surchargée"
msgid "Analysis already performed"
msgstr "Analyse déjà effectuée"
@ -294,21 +311,17 @@ msgstr "Défilement dans les bords\\Défilement lorsque la souris touche les bor
msgid "Camera closer\\Moves the camera forward"
msgstr "Caméra plus proche\\Avance la caméra"
#, fuzzy
msgid "Camera down\\Turns the camera down"
msgstr "Caméra plus proche\\Avance la caméra"
msgstr "Baisser caméra\\Baisse la caméra"
#, fuzzy
msgid "Camera left\\Turns the camera left"
msgstr "Caméra plus proche\\Avance la caméra"
msgstr "Caméra à gauche\\Tourne la caméra vers la gauche"
#, fuzzy
msgid "Camera right\\Turns the camera right"
msgstr "Tourner à droite\\Moteur à droite"
msgstr "Caméra à droite\\Tourne la caméra vers la droite"
#, fuzzy
msgid "Camera up\\Turns the camera up"
msgstr "Caméra (\\key camera;)"
msgstr "Lever caméra\\Monte la caméra"
msgid "Can not produce not researched object"
msgstr "Impossible de créer un objet n'ayant pas été recherché"
@ -349,6 +362,9 @@ msgstr "Console de triche\\Montre la console de triche"
msgid "Checkpoint"
msgstr "Indicateur"
msgid "Class name expected"
msgstr ""
msgid "Climb\\Increases the power of the jet"
msgstr "Monter\\Augmenter la puissance du réacteur"
@ -364,6 +380,10 @@ msgstr "Fermer"
msgid "Closing bracket missing"
msgstr "Il manque une parenthèse fermante"
#, fuzzy
msgid "Code battle"
msgstr "Batailles de code"
msgid "Code battles"
msgstr "Batailles de code"
@ -519,7 +539,7 @@ msgid "Explosive"
msgstr "Explosif"
msgid "Expression expected after ="
msgstr ""
msgstr "Expression attendue après ="
msgid "Extend shield (\\key action;)"
msgstr "Déploie le bouclier (\\key action;)"
@ -606,6 +626,9 @@ msgstr "Cette fonction existe déjà"
msgid "Function name missing"
msgstr "Nom de la fonction attendu"
msgid "Function needs return type \"void\""
msgstr ""
msgid "Game speed"
msgstr "Vitesse du jeu"
@ -730,7 +753,7 @@ msgid "Internal error - tell the developers"
msgstr "Erreur interne - contacter les développeurs"
msgid "Invert\\Invert values on this axis"
msgstr ""
msgstr "Inversion\\Inverse les valeurs sur cet axe"
msgid "Jet temperature"
msgstr "Température du réacteur"
@ -921,6 +944,9 @@ msgstr "Pas d'uranium à transformer"
msgid "No userlevels installed!"
msgstr "Pas de niveaux spéciaux installés !"
msgid "Non-void function needs \"return;\""
msgstr ""
msgid "Normal size"
msgstr "Taille normale"
@ -1024,10 +1050,10 @@ msgid "Paste (Ctrl+V)"
msgstr "Coller (Ctrl+V)"
msgid "Pause blur\\Blur the background on the pause screen"
msgstr ""
msgstr "Flouter les pauses\\Floute le fond de l'écran de pause"
msgid "Pause in background\\Pause the game when the window is unfocused"
msgstr ""
msgstr "Pause en arrière-plan\\Met le jeu en pause quand la fenêtre n'a plus le focus"
msgid "Pause/continue"
msgstr "Pause/continuer"
@ -1219,15 +1245,18 @@ msgid "Resolution:"
msgstr "Résolutions :"
msgid "Resources"
msgstr ""
msgstr "Ressources"
msgid "Restart\\Restart the mission from the beginning"
msgstr "Recommencer\\Recommencer la mission au début"
msgid "Restoring CBot execution state"
msgstr ""
msgstr "Restaurer l'état d'exécution CBOT"
msgid "Restoring saved objects"
msgstr "Restaurer des objets sauvés"
msgid "Results"
msgstr ""
msgid "Return to start"
@ -1452,6 +1481,9 @@ msgstr "Filtrage de textures\\Filtrage de textures"
msgid "Textures"
msgstr "Textures"
msgid "The battle has ended"
msgstr ""
msgid "The expression must return a boolean value"
msgstr "L'expression doit ętre un boolean"
@ -1482,9 +1514,15 @@ msgstr "Cette étiquette n'existe pas"
msgid "This menu is for userlevels from mods, but you didn't install any"
msgstr "Ce menu donne accès aux niveaux spéciaux (importés ou personnalisés), mais aucun n'est installé."
msgid "This object is currently busy"
msgstr ""
msgid "This object is not a member of a class"
msgstr "L'objet n'est pas une instance d'une classe"
msgid "This parameter needs a default value"
msgstr ""
msgid "This program is read-only, clone it to edit"
msgstr "Ce programme est en lecture-seule, le dupliquer pour pouvoir l'éditer"
@ -1677,24 +1715,24 @@ msgstr "Vous ne pouvez pas transporter un objet radioactif"
msgid "You can not carry an object under water"
msgstr "Vous ne pouvez pas transporter un objet sous l'eau"
#, fuzzy, c-format
#, c-format
msgid "You cannot use \"%s\" in this exercise (used: %d)"
msgstr "Interdit dans cet exercice"
msgstr "Vous ne pouvez pas utiliser «%s» dans cet exercice (utilisé : %d)"
msgid "You found a usable object"
msgstr "Vous avez trouvé un objet utilisable"
#, fuzzy, c-format
#, c-format
msgid "You have to use \"%1$s\" at least once in this exercise (used: %2$d)"
msgid_plural "You have to use \"%1$s\" at least %3$d times in this exercise (used: %2$d)"
msgstr[0] "Interdit dans cet exercice"
msgstr[1] "Interdit dans cet exercice"
msgstr[0] "Vous devez utiliser «%1$s» au moins une fois dans cet exercice (utilisé %2$d fois)"
msgstr[1] "Vous devez utiliser «%1$s» au moins %3$d fois dans cet exercice (utilisé %2$d fois)"
#, fuzzy, c-format
#, c-format
msgid "You have to use \"%1$s\" at most once in this exercise (used: %2$d)"
msgid_plural "You have to use \"%1$s\" at most %3$d times in this exercise (used: %2$d)"
msgstr[0] "Interdit dans cet exercice"
msgstr[1] "Interdit dans cet exercice"
msgstr[0] "Vous devez utiliser «%1$s» au plus une fois dans cet exercice (utilisé %2$d fois)"
msgstr[1] "Vous devez utiliser «%1$s» au plus %3$d fois dans cet exercice (utilisé %2$d fois)"
msgid "You must get on the spaceship to take off"
msgstr "Vous devez embarquer pour pouvoir décoller"
@ -1864,9 +1902,8 @@ msgstr "epsitec.com"
#~ msgid "Developed by :"
#~ msgstr "Développé par :"
#, fuzzy
#~ msgid "Do you want to quit Colobot: Gold Edition?"
#~ msgstr "Voulez-vous quitter COLOBOT ?"
#~ msgstr "Voulez-vous quitter Colobot: Édition Gold ?"
#~ msgid "Exit film\\Film at the exit of exercises"
#~ msgstr "Retour animé\\Retour animé dans les exercices"

View File

@ -27,6 +27,10 @@ msgstr "Oczekiwane \" [ \""
msgid "\" ] \" missing"
msgstr "Brak \" ] \""
#, c-format
msgid "%s: %d pts"
msgstr "%s: %d pkt"
msgid "..behind"
msgstr "..za"
@ -48,6 +52,18 @@ msgstr "<< Wstecz \\Wraca do poprzedniego ekranu"
msgid "<<< Sorry; mission failed >>>"
msgstr "<<< Niestety, misja nie powiodła się >>>"
#, c-format
msgid "<<< Team %s finished! >>>"
msgstr "<<< Drużyna %s zakończyła rozgrywkę! >>>"
#, c-format
msgid "<<< Team %s lost! >>>"
msgstr "<<< Drużyna %s odpadła! >>>"
#, c-format
msgid "<<< Team %s recieved %d points >>>"
msgstr "<<< Drużyna %s zdobyła %d punktów >>>"
msgid "<<< Well done; mission accomplished >>>"
msgstr "<<< Dobra robota, misja wypełniona >>>"
@ -348,6 +364,9 @@ msgstr "Konsola komend\\Pokaż konsolę komend"
msgid "Checkpoint"
msgstr "Punkt kontrolny"
msgid "Class name expected"
msgstr ""
msgid "Climb\\Increases the power of the jet"
msgstr "W górę\\Zwiększa moc silnika"
@ -363,6 +382,9 @@ msgstr "Zamknij"
msgid "Closing bracket missing"
msgstr "Brak nawiasu zamykającego"
msgid "Code battle"
msgstr "Programobitwa"
msgid "Code battles"
msgstr "Programobitwy"
@ -605,6 +627,9 @@ msgstr "Funkcja już istnieje"
msgid "Function name missing"
msgstr "Brakująca nazwa funkcji"
msgid "Function needs return type \"void\""
msgstr ""
msgid "Game speed"
msgstr "Prędkość gry"
@ -920,6 +945,9 @@ msgstr "Brak uranu do przetworzenia"
msgid "No userlevels installed!"
msgstr "Brak zainstalowanych poziomów użytkownika!"
msgid "Non-void function needs \"return;\""
msgstr ""
msgid "Normal size"
msgstr "Normalna wielkość"
@ -1229,6 +1257,9 @@ msgstr "Przywracanie stanu CBot"
msgid "Restoring saved objects"
msgstr "Przywracanie obiektów"
msgid "Results"
msgstr "Wyniki"
msgid "Return to start"
msgstr "Powrót do początku"
@ -1451,6 +1482,9 @@ msgstr "Filtrowanie tekstur\\Filtrowanie tekstur"
msgid "Textures"
msgstr "Tekstury"
msgid "The battle has ended"
msgstr "Bitwa zakończyła się"
msgid "The expression must return a boolean value"
msgstr "Wyrażenie musi zwrócić wartość logiczną"
@ -1481,9 +1515,15 @@ msgstr "Taka etykieta nie istnieje"
msgid "This menu is for userlevels from mods, but you didn't install any"
msgstr "To menu jest przeznaczone na poziomy użytkownika z modyfikacji, ale żadne nie są zainstalowane"
msgid "This object is currently busy"
msgstr "Ten objekt jest obecnie zajęty"
msgid "This object is not a member of a class"
msgstr "Ten obiekt nie jest członkiem klasy"
msgid "This parameter needs a default value"
msgstr ""
msgid "This program is read-only, clone it to edit"
msgstr "Ten program jest tylko do odczytu, skopiuj go, aby edytować"

View File

@ -27,6 +27,10 @@ msgstr "Ожидалось \" [ \""
msgid "\" ] \" missing"
msgstr "Отсутствует \"]\" "
#, c-format
msgid "%s: %d pts"
msgstr ""
msgid "..behind"
msgstr "Сзади"
@ -48,6 +52,18 @@ msgstr "<< Назад \\Вернуться на предыдущую стран
msgid "<<< Sorry; mission failed >>>"
msgstr "<<< Миссия провалена >>>"
#, c-format
msgid "<<< Team %s finished! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s lost! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s recieved %d points >>>"
msgstr ""
msgid "<<< Well done; mission accomplished >>>"
msgstr "<<< Отлично, миссия выполнена >>>"
@ -85,7 +101,7 @@ msgid "Alternative camera mode\\Move sideways instead of rotating (in free camer
msgstr "Альтернативный режим камеры\\Движение в стороны вместо поворачивания (в режиме свободной камеры)"
msgid "Ambiguous call to overloaded function"
msgstr ""
msgstr "Странный вызов перегруженной функции"
msgid "Analysis already performed"
msgstr "Анализ уже выполнен"
@ -353,6 +369,9 @@ msgstr "Консоль чит-кодов\\Показать консоль для
msgid "Checkpoint"
msgstr "Контрольная точка"
msgid "Class name expected"
msgstr ""
msgid "Climb\\Increases the power of the jet"
msgstr "Взлет и подъем\\Увеличивает мощность реактивного двигателя"
@ -369,11 +388,15 @@ msgstr "Закрыть"
msgid "Closing bracket missing"
msgstr "Закрывающая скобка отсутствует"
#, fuzzy
msgid "Code battle"
msgstr "Битвы роботов"
msgid "Code battles"
msgstr ""
msgstr "Битвы роботов"
msgid "Code battles\\Program your robot to be the best of them all!"
msgstr "Code battles\\Запрограммируйте собственного робота чтобы быть лучшим среди них!"
msgstr "Битвы роботов\\Запрограммируйте собственного робота чтобы быть лучшим среди них!"
msgid "Colobot rules!"
msgstr "Правила игры!"
@ -612,6 +635,9 @@ msgstr "Функция уже существует"
msgid "Function name missing"
msgstr "Имя функции отсутствует"
msgid "Function needs return type \"void\""
msgstr ""
msgid "Game speed"
msgstr "Скорость игры"
@ -817,7 +843,7 @@ msgid "Lunar Roving Vehicle"
msgstr "Луноход"
msgid "MSAA\\Multisample anti-aliasing"
msgstr ""
msgstr "MSAA\\Улучшенная фильтрация"
msgid "Maximize"
msgstr "Развернуть"
@ -826,7 +852,7 @@ msgid "Minimize"
msgstr "Свернуть"
msgid "Mipmap level\\Mipmap level"
msgstr ""
msgstr "Уровень уменьшающей фильтрации\\Уровень уменьшающей фильтрации"
msgid "Mission name"
msgstr "Название миссии"
@ -929,6 +955,9 @@ msgstr "Нет урана для преобразования"
msgid "No userlevels installed!"
msgstr "Не установленны пользовательские уровни!"
msgid "Non-void function needs \"return;\""
msgstr ""
msgid "Normal size"
msgstr "Нормальный размер"
@ -1230,17 +1259,20 @@ msgid "Resolution:"
msgstr "Разрешение:"
msgid "Resources"
msgstr ""
msgstr "Ресурсы"
msgid "Restart\\Restart the mission from the beginning"
msgstr "Заново\\Начать данную миссию с начала"
msgid "Restoring CBot execution state"
msgstr ""
msgstr "Восстановление состояния CBot"
msgid "Restoring saved objects"
msgstr "Восстановить сохранённые объекты"
msgid "Results"
msgstr ""
msgid "Return to start"
msgstr "Вернуться в начало"
@ -1465,6 +1497,9 @@ msgstr "Фильтрация текстур\\Фильтрация текстур
msgid "Textures"
msgstr "Текстуры"
msgid "The battle has ended"
msgstr ""
msgid "The expression must return a boolean value"
msgstr "Выражение должно возвращать логическое значение"
@ -1495,9 +1530,15 @@ msgstr "Эта метка не существует"
msgid "This menu is for userlevels from mods, but you didn't install any"
msgstr "Это меню для пользовательских уровней из модов, но вы ни одного не уставили"
msgid "This object is currently busy"
msgstr ""
msgid "This object is not a member of a class"
msgstr "Этот объект не член класса"
msgid "This parameter needs a default value"
msgstr ""
msgid "This program is read-only, clone it to edit"
msgstr "Эта программа только для чтения, для редактирования клонируйте её"

View File

@ -350,7 +350,7 @@ CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nId
val = m_prog->GetExternalCalls()->CompileCall(p, nullptr, ppVars, this);
if (val.GetType() < 0)
{
val = m_prog->GetFunctions()->CompileCall(p->GetString(), ppVars, nIdent);
val = CBotFunction::CompileCall(m_prog->GetFunctions(), p->GetString(), ppVars, nIdent);
if ( val.GetType() < 0 )
{
// pVar = nullptr; // the error is not on a particular parameter
@ -369,8 +369,7 @@ bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam)
if ( m_prog->GetExternalCalls()->CheckCall(name) ) return true;
CBotFunction* pp = m_prog->GetFunctions();
while ( pp != nullptr )
for (CBotFunction* pp : m_prog->GetFunctions())
{
if ( pToken->GetString() == pp->GetName() )
{
@ -378,7 +377,6 @@ bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam)
if ( pp->CheckParam( pParam ) )
return true;
}
pp = pp->Next();
}
for (CBotFunction* pp : CBotFunction::m_publicFunctions)

View File

@ -1,113 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "CBot/CBotCallMethode.h"
#include "CBot/CBotUtils.h"
#include "CBot/CBotStack.h"
#include "CBot/CBotCStack.h"
#include "CBot/CBotVar/CBotVar.h"
namespace CBot
{
////////////////////////////////////////////////////////////////////////////////
CBotCallMethode::CBotCallMethode(const std::string& name,
bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user),
CBotTypResult rCompile(CBotVar* pThis, CBotVar*& pVar))
{
m_name = name;
m_rExec = rExec;
m_rComp = rCompile;
}
////////////////////////////////////////////////////////////////////////////////
CBotCallMethode::~CBotCallMethode()
{
}
////////////////////////////////////////////////////////////////////////////////
CBotTypResult CBotCallMethode::CompileCall(const std::string& name, CBotVar* pThis, CBotVar** ppVar,
CBotCStack* pStack)
{
CBotCallMethode* pt = this;
while ( pt != nullptr )
{
if ( pt->m_name == name )
{
CBotVar* pVar = MakeListVars(ppVar, true);
CBotVar* pVar2 = pVar;
CBotTypResult r = pt->m_rComp(pThis, pVar2);
int ret = r.GetType();
if ( ret > 20 )
{
if (pVar2) pStack->SetError(static_cast<CBotError>(ret), pVar2->GetToken());
}
delete pVar;
return r;
}
pt = pt->m_next;
}
return CBotTypResult(-1);
}
////////////////////////////////////////////////////////////////////////////////
int CBotCallMethode::DoCall(const std::string& name, CBotVar* pThis, CBotVar** ppVars, CBotVar*& pResult,
CBotStack* pStack, CBotToken* pToken)
{
CBotCallMethode* pt = this;
// search by name
while ( pt != nullptr )
{
if ( pt->m_name == name )
{
// lists the parameters depending on the contents of the stack (pStackVar)
CBotVar* pVar = MakeListVars(ppVars, true);
CBotVar* pVarToDelete = pVar;
int Exception = 0; // TODO: Change this to CBotError
int res = pt->m_rExec(pThis, pVar, pResult, Exception, pStack->GetUserPtr());
pStack->SetVar(pResult);
if (res == false)
{
if (Exception!=0)
{
// pStack->SetError(Exception, pVar->GetToken());
pStack->SetError(static_cast<CBotError>(Exception), pToken);
}
delete pVarToDelete;
return false;
}
delete pVarToDelete;
return true;
}
pt = pt->m_next;
}
return -1;
}
} // namespace CBot

View File

@ -1,88 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "CBot/CBotTypResult.h"
#include "CBot/CBotUtils.h"
namespace CBot
{
class CBotVar;
class CBotCStack;
class CBotStack;
class CBotToken;
/*!
* \brief The CBotCallMethode class Class managing the methods declared by
* AddFunction on a class.
*/
class CBotCallMethode : public CBotLinkedList<CBotCallMethode>
{
public:
/*!
* \brief CBotCallMethode
* \param name
* \param rExec
* \param rCompile
*/
CBotCallMethode(const std::string& name,
bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user),
CBotTypResult rCompile(CBotVar* pThis, CBotVar*& pVar));
/*!
* \brief ~CBotCallMethode
*/
~CBotCallMethode();
/*!
* \brief CompileCall Is acceptable by a call procedure name and given
* parameters.
* \param name
* \param pThis
* \param ppVars
* \param pStack
* \return
*/
CBotTypResult CompileCall(const std::string& name, CBotVar* pThis, CBotVar** ppVars,
CBotCStack* pStack);
/*!
* \brief DoCall
* \param name
* \param pThis
* \param ppVars
* \param pResult
* \param pStack
* \param pFunc
* \return
*/
int DoCall(const std::string& name, CBotVar* pThis, CBotVar** ppVars, CBotVar*& pResult,
CBotStack* pStack, CBotToken* pFunc);
private:
std::string m_name;
bool (*m_rExec) (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user);
CBotTypResult (*m_rComp) (CBotVar* pThis, CBotVar* &pVar);
friend class CBotClass;
};
} // namespace CBot

View File

@ -37,7 +37,6 @@
#include "CBot/CBotDefParam.h"
#include "CBot/CBotUtils.h"
#include "CBot/CBotFileUtils.h"
#include "CBot/CBotCallMethode.h"
#include <algorithm>
@ -55,8 +54,7 @@ CBotClass::CBotClass(const std::string& name,
m_parent = parent;
m_name = name;
m_pVar = nullptr;
m_pCalls = nullptr;
m_pMethod = nullptr;
m_externalMethods = new CBotExternalCallList();
m_rUpdate = nullptr;
m_IsDef = true;
m_bIntrinsic= bIntrinsic;
@ -71,8 +69,7 @@ CBotClass::~CBotClass()
m_publicClasses.erase(this);
delete m_pVar;
delete m_pCalls;
delete m_pMethod;
delete m_externalMethods;
}
////////////////////////////////////////////////////////////////////////////////
@ -86,26 +83,24 @@ CBotClass* CBotClass::Create(const std::string& name,
////////////////////////////////////////////////////////////////////////////////
void CBotClass::ClearPublic()
{
m_publicClasses.clear();
while ( !m_publicClasses.empty() )
{
auto it = m_publicClasses.begin();
delete *it; // calling destructor removes the class from the list
}
}
////////////////////////////////////////////////////////////////////////////////
void CBotClass::Purge()
{
assert ( this != nullptr );
delete m_pVar;
m_pVar = nullptr;
delete m_pCalls;
m_pCalls = nullptr;
delete m_pMethod;
m_pMethod = nullptr;
m_externalMethods->Clear();
for (CBotFunction* f : m_pMethod) delete f;
m_pMethod.clear();
m_IsDef = false;
m_nbVar = m_parent == nullptr ? 0 : m_parent->m_nbVar;
if (m_next != nullptr) m_next->Purge();
m_next = nullptr; // no longer belongs to this chain
}
////////////////////////////////////////////////////////////////////////////////
@ -205,7 +200,6 @@ std::string CBotClass::GetName()
////////////////////////////////////////////////////////////////////////////////
CBotClass* CBotClass::GetParent()
{
assert ( this != nullptr );
return m_parent;
}
@ -255,6 +249,19 @@ CBotVar* CBotClass::GetItemRef(int nIdent)
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotClass::CheckVar(const std::string &name)
{
CBotVar* p = m_pVar;
while ( p != nullptr )
{
if ( p->GetName() == name ) return true;
p = p->GetNext();
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotClass::IsIntrinsic()
{
@ -283,29 +290,7 @@ bool CBotClass::AddFunction(const std::string& name,
bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user),
CBotTypResult rCompile(CBotVar* pThis, CBotVar*& pVar))
{
// stores pointers to the two functions
CBotCallMethode* p = m_pCalls;
CBotCallMethode* pp = nullptr;
while ( p != nullptr )
{
if ( name == p->m_name )
{
if ( pp == nullptr ) m_pCalls = p->m_next;
else pp->m_next = p->m_next;
delete p;
break;
}
pp = p;
p = p->m_next;
}
p = new CBotCallMethode(name, rExec, rCompile);
if (m_pCalls == nullptr) m_pCalls = p;
else m_pCalls->AddNext(p); // added to the list
return true;
return m_externalMethods->AddFunction(name, std::unique_ptr<CBotExternalCall>(new CBotExternalCallClass(rExec, rCompile)));
}
////////////////////////////////////////////////////////////////////////////////
@ -316,7 +301,7 @@ bool CBotClass::SetUpdateFunc(void rUpdate(CBotVar* thisVar, void* user))
}
////////////////////////////////////////////////////////////////////////////////
CBotTypResult CBotClass::CompileMethode(const std::string& name,
CBotTypResult CBotClass::CompileMethode(CBotToken* name,
CBotVar* pThis,
CBotVar** ppParams,
CBotCStack* pStack,
@ -326,12 +311,12 @@ CBotTypResult CBotClass::CompileMethode(const std::string& name,
// find the methods declared by AddFunction
CBotTypResult r = m_pCalls->CompileCall(name, pThis, ppParams, pStack);
CBotTypResult r = m_externalMethods->CompileCall(name, pThis, ppParams, pStack);
if ( r.GetType() >= 0) return r;
// find the methods declared by user
r = m_pMethod->CompileCall(name, ppParams, nIdent);
r = CBotFunction::CompileCall(m_pMethod, name->GetString(), ppParams, nIdent);
if ( r.Eq(CBotErrUndefCall) && m_parent != nullptr )
return m_parent->CompileMethode(name, pThis, ppParams, pStack, nIdent);
return r;
@ -339,37 +324,39 @@ CBotTypResult CBotClass::CompileMethode(const std::string& name,
////////////////////////////////////////////////////////////////////////////////
bool CBotClass::ExecuteMethode(long& nIdent,
const std::string& name,
CBotVar* pThis,
CBotVar** ppParams,
CBotVar*& pResult,
CBotTypResult pResultType,
CBotStack*& pStack,
CBotToken* pToken)
{
int ret = m_pCalls->DoCall(name, pThis, ppParams, pResult, pStack, pToken);
int ret = m_externalMethods->DoCall(pToken, pThis, ppParams, pStack, pResultType);
if (ret >= 0) return ret;
ret = m_pMethod->DoCall(nIdent, name, pThis, ppParams, pStack, pToken, this);
ret = CBotFunction::DoCall(m_pMethod, nIdent, pToken->GetString(), pThis, ppParams, pStack, pToken, this);
if (ret >= 0) return ret;
if (m_parent != nullptr)
{
ret = m_parent->ExecuteMethode(nIdent, name, pThis, ppParams, pResult, pStack, pToken);
ret = m_parent->ExecuteMethode(nIdent, pThis, ppParams, pResultType, pStack, pToken);
}
return ret;
}
////////////////////////////////////////////////////////////////////////////////
void CBotClass::RestoreMethode(long& nIdent,
const std::string& name,
CBotToken* name,
CBotVar* pThis,
CBotVar** ppParams,
CBotStack*& pStack)
{
if (m_externalMethods->RestoreCall(name, pThis, ppParams, pStack))
return;
CBotClass* pClass = this;
while (pClass != nullptr)
{
bool ok = pClass->m_pMethod->RestoreCall(nIdent, name, pThis, ppParams, pStack, pClass);
bool ok = CBotFunction::RestoreCall(pClass->m_pMethod, nIdent, name->GetString(), pThis, ppParams, pStack, pClass);
if (ok) return;
pClass = pClass->m_parent;
}
@ -455,8 +442,7 @@ bool CBotClass::CheckCall(CBotProgram* program, CBotDefParam* pParam, CBotToken*
if ( program->GetExternalCalls()->CheckCall(name) ) return true;
CBotFunction* pp = m_pMethod;
while ( pp != nullptr )
for (CBotFunction* pp : m_pMethod)
{
if ( pToken->GetString() == pp->GetName() )
{
@ -464,7 +450,6 @@ bool CBotClass::CheckCall(CBotProgram* program, CBotDefParam* pParam, CBotToken*
if ( pp->CheckParam( pParam ) )
return true;
}
pp = pp->Next();
}
return false;
@ -483,30 +468,32 @@ CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
std::string name = p->GetString();
CBotClass* pOld = CBotClass::Find(name);
if ( pOld != nullptr && pOld->m_IsDef )
{
pStack->SetError( CBotErrRedefClass, p );
return nullptr;
}
// a name of the class is there?
if (IsOfType(p, TokenTypVar))
{
CBotClass* pOld = CBotClass::Find(name);
if ((pOld != nullptr && pOld->m_IsDef) || /* public class exists in different program */
pStack->GetProgram()->ClassExists(name)) /* class exists in this program */
{
pStack->SetError(CBotErrRedefClass, p->GetPrev());
return nullptr;
}
CBotClass* pPapa = nullptr;
if ( IsOfType( p, ID_EXTENDS ) )
{
std::string name = p->GetString();
pPapa = CBotClass::Find(name);
CBotToken* pp = p;
if (!IsOfType(p, TokenTypVar) || pPapa == nullptr )
{
pStack->SetError( CBotErrNotClass, p );
pStack->SetError(CBotErrNoClassName, pp);
return nullptr;
}
}
CBotClass* classe = (pOld == nullptr) ? new CBotClass(name, pPapa) : pOld;
classe->Purge(); // empty the old definitions // TODO: Doesn't this remove all classes of the current program?
classe->Purge(); // empty the old definitions
classe->m_IsDef = false; // current definition
classe->m_pOpenblk = p;
@ -518,27 +505,29 @@ CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
}
int level = 1;
do // skip over the definition
while (level > 0 && p != nullptr)
{
int type = p->GetType();
p = p->GetNext();
if (type == ID_OPBLK) level++;
if (type == ID_CLBLK) level--;
}
while (level > 0 && p != nullptr);
if (level > 0) pStack->SetError(CBotErrCloseBlock, classe->m_pOpenblk);
if (pStack->IsOk()) return classe;
}
else
pStack->SetError(CBotErrNoClassName, p);
pStack->SetError(CBotErrNoTerminator, p);
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
void CBotClass::DefineClasses(CBotClass* pClass, CBotCStack* pStack)
void CBotClass::DefineClasses(std::list<CBotClass*> pClassList, CBotCStack* pStack)
{
while (pClass != nullptr)
for (CBotClass* pClass : pClassList)
{
CBotClass* pParent = pClass->m_parent;
pClass->m_nbVar = (pParent == nullptr) ? 0 : pParent->m_nbVar;
@ -550,8 +539,6 @@ void CBotClass::DefineClasses(CBotClass* pClass, CBotCStack* pStack)
}
if (!pStack->IsOk()) return;
pClass = pClass->GetNext();
}
}
@ -587,6 +574,8 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
while (pStack->IsOk())
{
CBotTypResult type2 = CBotTypResult(type); // reset type after comma
CBotToken* varToken = p;
std::string pp = p->GetString();
if ( IsOfType(p, ID_NOT) )
{
@ -595,60 +584,30 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
if (IsOfType(p, TokenTypVar))
{
CBotInstr* limites = nullptr;
while ( IsOfType( p, ID_OPBRK ) ) // a table?
{
CBotInstr* i = nullptr;
pStack->SetStartError( p->GetStart() );
if ( p->GetType() != ID_CLBRK )
{
i = CBotExpression::Compile( p, pStack ); // expression for the value
if (i == nullptr || pStack->GetType() != CBotTypInt) // must be a number
{
pStack->SetError(CBotErrBadIndex, p->GetStart());
return false;
}
}
else
i = new CBotEmpty(); // special if not a formula
type2 = CBotTypResult(CBotTypArrayPointer, type2);
if (limites == nullptr) limites = i;
else limites->AddNext3(i);
if (IsOfType(p, ID_CLBRK)) continue;
pStack->SetError(CBotErrCloseIndex, p->GetStart());
return false;
}
if ( p->GetType() == ID_OPENPAR )
{
if ( !bSecond )
{
p = pBase;
CBotFunction* f =
CBotFunction::Compile1(p, pStack, this);
CBotFunction* f = CBotFunction::Compile1(p, pStack, this);
if ( f == nullptr ) return false;
if (m_pMethod == nullptr) m_pMethod = f;
else m_pMethod->AddNext(f);
m_pMethod.push_back(f);
}
else
{
// return a method precompiled in pass 1
CBotFunction* pf = m_pMethod;
CBotToken* ppp = p;
CBotCStack* pStk = pStack->TokenStack(nullptr, true);
CBotDefParam* params = CBotDefParam::Compile(p, pStk );
delete pStk;
p = ppp;
while ( pf != nullptr ) // search by name and parameters
std::list<CBotFunction*>::iterator pfIter = std::find_if(m_pMethod.begin(), m_pMethod.end(), [&pp, &params](CBotFunction* x)
{
if (pf->GetName() == pp && pf->CheckParam( params )) break;
pf = pf->Next();
}
return x->GetName() == pp && x->CheckParam( params );
});
assert(pfIter != m_pMethod.end());
CBotFunction* pf = *pfIter;
delete params;
bool bConstructor = (pp == GetName());
CBotCStack* pile = pStack->TokenStack(nullptr, true);
@ -706,12 +665,51 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
}
// definition of an element
if (type2.Eq(0))
if (type.Eq(0))
{
pStack->SetError(CBotErrNoTerminator, p);
return false;
}
if (pp[0] == '~' || pp == GetName()) // bad variable name
{
pStack->SetError(CBotErrNoVar, varToken);
return false;
}
if (!bSecond && CheckVar(pp)) // variable already exists
{
pStack->SetError(CBotErrRedefVar, varToken);
return false;
}
CBotInstr* limites = nullptr;
while ( IsOfType( p, ID_OPBRK ) ) // an array
{
CBotInstr* i = nullptr;
pStack->SetStartError( p->GetStart() );
if ( p->GetType() != ID_CLBRK )
{
i = CBotExpression::Compile( p, pStack ); // expression for the value
if (i == nullptr || pStack->GetType() != CBotTypInt) // must be a number
{
pStack->SetError(CBotErrBadIndex, p->GetStart());
}
}
else
i = new CBotEmpty(); // special if not a formula
type2 = CBotTypResult(CBotTypArrayPointer, type2);
if (limites == nullptr) limites = i;
else limites->AddNext3(i);
if (pStack->IsOk() && IsOfType(p, ID_CLBRK)) continue;
pStack->SetError(CBotErrCloseIndex, p->GetStart());
delete limites;
return false;
}
CBotInstr* i = nullptr;
if ( IsOfType(p, ID_ASS ) )
{
@ -781,7 +779,10 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
}
}
else
{
delete i;
delete limites;
}
if ( IsOfType(p, ID_COMMA) ) continue;
if ( IsOfType(p, ID_SEP) ) break;
@ -810,10 +811,11 @@ CBotClass* CBotClass::Compile(CBotToken* &p, CBotCStack* pStack)
// TODO: Not sure how correct is that - I have no idea how the precompilation (Compile1 method) works ~krzys_h
std::string name = p->GetString();
CBotClass* pPapa = CBotClass::Find(name);
CBotToken* pp = p;
if (!IsOfType(p, TokenTypVar) || pPapa == nullptr)
{
pStack->SetError( CBotErrNotClass, p );
pStack->SetError(CBotErrNoClassName, pp);
return nullptr;
}
pOld->m_parent = pPapa;

View File

@ -26,6 +26,7 @@
#include <string>
#include <deque>
#include <set>
#include <list>
namespace CBot
{
@ -37,6 +38,7 @@ class CBotStack;
class CBotDefParam;
class CBotToken;
class CBotCStack;
class CBotExternalCallList;
/**
* \brief A CBot class definition
@ -102,7 +104,7 @@ class CBotCStack;
* float y = var->GetValFloat();
* \endcode
*/
class CBotClass : public CBotLinkedList<CBotClass>
class CBotClass
{
public:
/*!
@ -133,13 +135,8 @@ public:
bool intrinsic = false);
/*!
* \brief AddFunction This call allows to add as external new method
* used by the objects of this class. See (**) at end of this file for
* more details.
* \param name
* \param rExec
* \param rCompile
* \return
* \brief Add a function that can be called from CBot
* \see CBotProgram::AddFunction
*/
bool AddFunction(const std::string& name,
bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user),
@ -224,6 +221,13 @@ public:
*/
CBotVar* GetItemRef(int nIdent);
/*!
* \brief Check whether a variable is already defined in a class
* \param name Name of the variable
* \return True if a variable is defined in the class
*/
bool CheckVar(const std::string &name);
/*!
* \brief CompileMethode Compiles a method associated with an instance of
* class the method can be declared by the user or AddFunction.
@ -234,7 +238,7 @@ public:
* \param nIdent
* \return
*/
CBotTypResult CompileMethode(const std::string& name,
CBotTypResult CompileMethode(CBotToken* name,
CBotVar* pThis,
CBotVar** ppParams,
CBotCStack* pStack,
@ -246,18 +250,13 @@ public:
* \param name
* \param pThis
* \param ppParams
* \param pResult
* \param pResultType
* \param pStack
* \param pToken
* \return
*/
bool ExecuteMethode(long& nIdent,
const std::string& name,
CBotVar* pThis,
CBotVar** ppParams,
CBotVar*& pResult,
CBotStack*& pStack,
CBotToken* pToken);
bool ExecuteMethode(long &nIdent, CBotVar* pThis, CBotVar** ppParams, CBotTypResult pResultType,
CBotStack*&pStack, CBotToken* pToken);
/*!
* \brief RestoreMethode Restored the execution stack.
@ -268,7 +267,7 @@ public:
* \param pStack
*/
void RestoreMethode(long &nIdent,
const std::string& name,
CBotToken* name,
CBotVar* pThis,
CBotVar** ppParams,
CBotStack*&pStack);
@ -283,10 +282,15 @@ public:
CBotCStack* pStack);
/*!
* \brief Compile1
* \param p
* \param pStack
* \return
* \brief Pre-compile a new class
* \param p[in, out] Pointer to first token of the class, will be updated to point to first token after the class definition
* \param pStack Compile stack
*
* This function is used to find the beginning and end of class definition.
*
* If any errors in the code are detected, this function will set the error on compile stack and return nullptr.
*
* \return Precompiled class, or nullptr in case of error
*/
static CBotClass* Compile1(CBotToken* &p,
CBotCStack* pStack);
@ -294,10 +298,10 @@ public:
/*!
* \brief DefineClasses Calls CompileDefItem for each class in a list
* of classes, defining fields and pre-compiling methods.
* \param pClass List of classes
* \param pClassList List of classes
* \param pStack
*/
static void DefineClasses(CBotClass* pClass, CBotCStack* pStack);
static void DefineClasses(std::list<CBotClass*> pClassList, CBotCStack* pStack);
/*!
* \brief CompileDefItem
@ -388,9 +392,9 @@ private:
//! Linked list of all class fields
CBotVar* m_pVar;
//! Linked list of all class external calls
CBotCallMethode* m_pCalls;
//! Linked list of all class methods
CBotFunction* m_pMethod;
CBotExternalCallList* m_externalMethods;
//! List of all class methods
std::list<CBotFunction*> m_pMethod{};
void (*m_rUpdate)(CBotVar* thisVar, void* user);
CBotToken* m_pOpenblk;

View File

@ -36,12 +36,10 @@ void CBotDebug::DumpCompiledProgram(CBotProgram* program)
std::stringstream ss;
ss << "digraph {" << std::endl;
CBotFunction* func = program->GetFunctions();
std::map<long, CBotFunction*> funcIdMap;
while (func != nullptr)
for (CBotFunction* func : program->GetFunctions())
{
funcIdMap[func->m_nFuncIdent] = func;
func = func->Next();
}
std::set<CBotInstr*> finished;
@ -111,9 +109,8 @@ void CBotDebug::DumpCompiledProgram(CBotProgram* program)
{
DumpInstr(program->m_entryPoint);
}
func = program->GetFunctions();
std::string prev = GetPointerAsString(program->m_entryPoint);
while (func != nullptr)
for (CBotFunction* func : program->GetFunctions())
{
if (func != program->m_entryPoint)
{
@ -122,8 +119,6 @@ void CBotDebug::DumpCompiledProgram(CBotProgram* program)
//ss << prev << " -> " << GetPointerAsString(func) << " [style=invis]" << std::endl;
prev = GetPointerAsString(func);
}
func = func->Next();
}
ss << "}" << std::endl;

View File

@ -19,6 +19,9 @@
#include "CBot/CBotDefParam.h"
#include "CBot/CBotInstr/CBotInstrUtils.h"
#include "CBot/CBotInstr/CBotParExpr.h"
#include "CBot/CBotUtils.h"
#include "CBot/CBotCStack.h"
@ -33,11 +36,13 @@ namespace CBot
CBotDefParam::CBotDefParam()
{
m_nIdent = 0;
m_expr = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
CBotDefParam::~CBotDefParam()
{
delete m_expr;
}
////////////////////////////////////////////////////////////////////////////////
@ -51,8 +56,9 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
if (IsOfType(p, ID_OPENPAR))
{
CBotDefParam* list = nullptr;
bool prevHasDefault = false;
while (!IsOfType(p, ID_CLOSEPAR))
if (!IsOfType(p, ID_CLOSEPAR)) while (true)
{
CBotDefParam* param = new CBotDefParam();
if (list == nullptr) list = param;
@ -77,6 +83,26 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
break;
}
if (IsOfType(p, ID_ASS)) // default value assignment
{
CBotCStack* pStk = pStack->TokenStack(nullptr, true);
if (nullptr != (param->m_expr = CBotParExpr::CompileLitExpr(p, pStk)))
{
CBotTypResult valueType = pStk->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
if (!TypesCompatibles(type, valueType))
pStack->SetError(CBotErrBadType1, p->GetPrev());
prevHasDefault = true;
}
else pStack->SetError(CBotErrNoExpression, p);
delete pStk;
}
else
if (prevHasDefault) pStack->SetError(CBotErrDefaultValue, p->GetPrev());
if (!pStack->IsOk()) break;
if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody);
CBotVar* var = CBotVar::Create(pp->GetString(), type); // creates the variable
// if ( pClass ) var->SetClass(pClass);
@ -85,11 +111,13 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
var->SetUniqNum(param->m_nIdent);
pStack->AddVar(var); // place on the stack
if (IsOfType(p, ID_COMMA) || p->GetType() == ID_CLOSEPAR)
continue;
}
if (IsOfType(p, ID_COMMA)) continue;
if (IsOfType(p, ID_CLOSEPAR)) break;
pStack->SetError(CBotErrClosePar, p->GetStart());
}
pStack->SetError(CBotErrNoVar, p->GetStart());
}
pStack->SetError(CBotErrNoType, p);
delete list;
return nullptr;
@ -106,40 +134,71 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
int i = 0;
CBotDefParam* p = this;
bool useDefault = false;
CBotStack* pile = pj->AddStack();
while ( p != nullptr )
{
pile = pile->AddStack();
if (pile->GetState() == 1) // already done?
{
if (ppVars != nullptr && ppVars[i] != nullptr) ++i;
p = p->m_next;
continue; // next param
}
CBotVar* pVar = nullptr;
if (useDefault || (ppVars == nullptr || ppVars[i] == nullptr))
{
assert(p->m_expr != nullptr);
useDefault = true;
if (!p->m_expr->Execute(pile)) return false; // interupt here
pVar = pile->GetVar();
}
else
pVar = ppVars[i];
pile->SetState(1); // mark this param done
// creates a local variable on the stack
CBotVar* newvar = CBotVar::Create(p->m_token.GetString(), p->m_type);
// serves to make the transformation of types:
if ( ppVars != nullptr && ppVars[i] != nullptr )
if ((useDefault && pVar != nullptr) ||
(ppVars != nullptr && pVar != nullptr))
{
switch (p->m_type.GetType())
{
case CBotTypInt:
newvar->SetValInt(ppVars[i]->GetValInt());
newvar->SetValInt(pVar->GetValInt());
newvar->SetInit(pVar->GetInit()); // copy nan
break;
case CBotTypFloat:
newvar->SetValFloat(ppVars[i]->GetValFloat());
newvar->SetValFloat(pVar->GetValFloat());
newvar->SetInit(pVar->GetInit()); // copy nan
break;
case CBotTypString:
newvar->SetValString(ppVars[i]->GetValString());
newvar->SetValString(pVar->GetValString());
break;
case CBotTypBoolean:
newvar->SetValInt(ppVars[i]->GetValInt());
newvar->SetValInt(pVar->GetValInt());
break;
case CBotTypIntrinsic:
(static_cast<CBotVarClass*>(newvar))->Copy(ppVars[i], false);
(static_cast<CBotVarClass*>(newvar))->Copy(pVar, false);
break;
case CBotTypPointer:
{
newvar->SetPointer(ppVars[i]->GetPointer());
newvar->SetPointer(pVar->GetPointer());
newvar->SetType(p->m_type); // keep pointer type
}
break;
case CBotTypArrayPointer:
{
newvar->SetPointer(ppVars[i]->GetPointer());
newvar->SetPointer(pVar->GetPointer());
}
break;
default:
@ -149,23 +208,41 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
newvar->SetUniqNum(p->m_nIdent);
pj->AddVar(newvar); // add a variable
p = p->m_next;
i++;
if (!useDefault) i++;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotDefParam::HasDefault()
{
return (m_expr != nullptr);
}
////////////////////////////////////////////////////////////////////////////////
void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain)
{
// int i = 0;
CBotDefParam* p = this;
CBotStack* pile = nullptr;
if (bMain) pile = pj->RestoreStack();
while ( p != nullptr )
{
if (bMain && pile != nullptr)
{
pile = pile->RestoreStack();
if (pile != nullptr && pile->GetState() == 0)
{
assert(p->m_expr != nullptr);
p->m_expr->RestoreState(pile, true);
return;
}
}
// creates a local variable on the stack
CBotVar* var = pj->FindVar(p->m_token.GetString());
var->SetUniqNum(p->m_nIdent);
if (var != nullptr) var->SetUniqNum(p->m_nIdent);
p = p->m_next;
}
}

View File

@ -63,6 +63,12 @@ public:
*/
bool Execute(CBotVar** ppVars, CBotStack* &pj);
/*!
* \brief Check if this parameter has a default value expression.
* \return true if the parameter was compiled with a default value.
*/
bool HasDefault();
/*!
* \brief RestoreState
* \param pj
@ -96,6 +102,9 @@ private:
//! Type of paramteter.
CBotTypResult m_type;
long m_nIdent;
//! Default value expression for the parameter.
CBotInstr* m_expr;
};
} // namespace CBot

View File

@ -237,6 +237,10 @@ enum CBotError : int
CBotErrNoPublic = 5042, //!< missing word "public"
CBotErrNoExpression = 5043, //!< expression expected after =
CBotErrAmbiguousCall = 5044, //!< ambiguous call to overloaded function
CBotErrFuncNotVoid = 5045, //!< function needs return type "void"
CBotErrNoClassName = 5046, //!< class name expected
CBotErrNoReturn = 5047, //!< non-void function needs "return;"
CBotErrDefaultValue = 5048, //!< this parameter needs a default value
// Runtime errors
CBotErrZeroDiv = 6000, //!< division by zero

View File

@ -168,4 +168,48 @@ bool CBotExternalCallDefault::Run(CBotVar* thisVar, CBotStack* pStack)
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CBotExternalCallClass::CBotExternalCallClass(RuntimeFunc rExec, CompileFunc rCompile)
{
m_rExec = rExec;
m_rComp = rCompile;
}
CBotExternalCallClass::~CBotExternalCallClass()
{
}
CBotTypResult CBotExternalCallClass::Compile(CBotVar* thisVar, CBotVar* args, void* user)
{
return m_rComp(thisVar, args);
}
bool CBotExternalCallClass::Run(CBotVar* thisVar, CBotStack* pStack)
{
if (pStack->IsCallFinished()) return true;
CBotStack* pile = pStack->AddStackExternalCall(this);
CBotVar* args = pile->GetVar();
CBotStack* pile2 = pile->AddStack();
CBotVar* result = pile2->GetVar();
int exception = CBotNoErr; // TODO: Change to CBotError
bool res = m_rExec(thisVar, args, result, exception, pStack->GetUserPtr());
if (!res)
{
if (exception != CBotNoErr)
{
pStack->SetError(static_cast<CBotError>(exception));
}
return false;
}
if (result != nullptr) pStack->SetCopyVar(result);
return true;
}
}

View File

@ -105,6 +105,36 @@ private:
CompileFunc m_rComp;
};
/**
* \brief Implementation of CBot external call for class methods, using compilation and runtime functions
*/
class CBotExternalCallClass : public CBotExternalCall
{
public:
typedef bool (*RuntimeFunc)(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user);
typedef CBotTypResult (*CompileFunc)(CBotVar* pThis, CBotVar*& pVar);
/**
* \brief Constructor
* \param rExec Runtime function
* \param rCompile Compilation function
* \see CBotProgram::AddFunction()
*/
CBotExternalCallClass(RuntimeFunc rExec, CompileFunc rCompile);
/**
* \brief Destructor
*/
virtual ~CBotExternalCallClass();
virtual CBotTypResult Compile(CBotVar* thisVar, CBotVar* args, void* user) override;
virtual bool Run(CBotVar* thisVar, CBotStack* pStack) override;
private:
RuntimeFunc m_rExec;
CompileFunc m_rComp;
};
/**
* \brief Class for mangaging CBot external calls

View File

@ -51,6 +51,9 @@ CBotDefClass::CBotDefClass()
////////////////////////////////////////////////////////////////////////////////
CBotDefClass::~CBotDefClass()
{
delete m_parameters;
delete m_exprRetVar;
delete m_expr;
delete m_var;
}
@ -131,7 +134,7 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p
{
// the constructor is there?
// std::string noname;
CBotTypResult r = pClass->CompileMethode(pClass->GetName(), var, ppVars, pStk, inst->m_nMethodeIdent);
CBotTypResult r = pClass->CompileMethode(&token, var, ppVars, pStk, inst->m_nMethodeIdent);
delete pStk->TokenStack(); // releases the supplement stack
int typ = r.GetType();
@ -246,9 +249,9 @@ bool CBotDefClass::Execute(CBotStack* &pj)
if (m_exprRetVar != nullptr) // Class c().method();
{
if (pile->IfStep()) return false;
if (pile->GetState() == 4)
{
if (pile->IfStep()) return false;
CBotStack* pile3 = pile->AddStack();
if (!m_exprRetVar->Execute(pile3)) return false;
pile3->SetVar(nullptr);
@ -369,11 +372,7 @@ bool CBotDefClass::Execute(CBotStack* &pj)
ppVars[i] = nullptr;
// creates a variable for the result
CBotVar* pResult = nullptr; // constructor still void
if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GetName(),
pThis, ppVars,
pResult, pile2, GetToken())) return false; // interrupt
if ( !pClass->ExecuteMethode(m_nMethodeIdent, pThis, ppVars, CBotTypResult(CBotTypVoid), pile2, GetToken())) return false; // interrupt
pThis->SetInit(CBotVar::InitType::DEF);
pThis->ConstructorSet(); // indicates that the constructor has been called
@ -483,9 +482,7 @@ void CBotDefClass::RestoreState(CBotStack* &pj, bool bMain)
ppVars[i] = nullptr;
// creates a variable for the result
// CBotVar* pResult = nullptr; // constructor still void
pClass->RestoreMethode(m_nMethodeIdent, pClass->GetName(), pThis, ppVars, pile2);
pClass->RestoreMethode(m_nMethodeIdent, pt, pThis, ppVars, pile2);
return;
}
}

View File

@ -41,7 +41,7 @@ CBotExprUnaire::~CBotExprUnaire()
}
////////////////////////////////////////////////////////////////////////////////
CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack)
CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral)
{
int op = p->GetType();
CBotToken* pp = p;
@ -52,7 +52,10 @@ CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack)
CBotExprUnaire* inst = new CBotExprUnaire();
inst->SetToken(pp);
if (nullptr != (inst->m_expr = CBotParExpr::Compile(p, pStk )))
if (!bLiteral) inst->m_expr = CBotParExpr::Compile(p, pStk);
else inst->m_expr = CBotParExpr::CompileLitExpr(p, pStk);
if (inst->m_expr != nullptr)
{
if (op == ID_ADD && pStk->GetType() < CBotTypBoolean) // only with the number
return pStack->Return(inst, pStk);

View File

@ -34,12 +34,13 @@ public:
~CBotExprUnaire();
/*!
* \brief Compile
* \param p
* \param pStack
* \return
* \brief Compile an expression with a unary operator
* \param p[in, out] Pointer to first token of the expression, will be updated to point to first token after the expression
* \param pStack Current compilation stack frame
* \param bLiteral If true, compiles only literal expressions Ex: ~11, -4.0, !false, not true
* \return The compiled instruction or nullptr
*/
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral = false);
/*!
* \brief Execute

View File

@ -44,7 +44,7 @@ CBotExprVar::~CBotExprVar()
}
////////////////////////////////////////////////////////////////////////////////
CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::ProtectionLevel privat)
CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, bool bCheckReadOnly)
{
// CBotToken* pDebut = p;
CBotCStack* pStk = pStack->TokenStack();
@ -67,7 +67,7 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot
if (ident > 0 && ident < 9000)
{
if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, privat))
if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, bCheckReadOnly))
{
pStk->SetError(CBotErrPrivate, p);
goto err;
@ -122,6 +122,8 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot
{
if (p->GetNext()->GetType() == ID_OPENPAR) // a method call?
{
if (bCheckReadOnly) goto err; // don't allow increment a method call "++"
CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var);
if (!pStk->IsOk()) goto err;
inst->AddNext3(i); // added after
@ -137,7 +139,7 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot
if (var != nullptr)
{
i->SetUniqNum(var->GetUniqNum());
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, privat))
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, bCheckReadOnly))
{
pStk->SetError(CBotErrPrivate, pp);
goto err;

View File

@ -40,14 +40,13 @@ public:
~CBotExprVar();
/*!
* \brief Compile
* \param p
* \param pStack
* \param privat
* \brief Compile an expression of a variable, possibly chained with index operators and/or dot operators
* \param p[in, out] Pointer to first token of the expression, will be updated to point to first token after the expression
* \param pStack Current compilation stack frame
* \param bCheckReadOnly True for operations that would modify the value of the variable
* \return
*/
static CBotInstr* Compile(CBotToken*& p, CBotCStack* pStack,
CBotVar::ProtectionLevel privat = CBotVar::ProtectionLevel::Protected);
static CBotInstr* Compile(CBotToken*& p, CBotCStack* pStack, bool bCheckReadOnly = false);
/*!
* \brief CompileMethode
@ -81,6 +80,8 @@ public:
*/
bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep);
using CBotInstr::ExecuteVar;
/*!
* \brief RestoreStateVar Fetch variable at runtime.
* \param pj

View File

@ -135,12 +135,11 @@ std::string CBotFieldExpr::GetDebugData()
}
////////////////////////////////////////////////////////////////////////////////
bool CBotFieldExpr::CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar,
CBotVar::ProtectionLevel privat)
bool CBotFieldExpr::CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar, bool bCheckReadOnly)
{
CBotVar::ProtectionLevel varPriv = pVar->GetPrivate();
if (privat == CBotVar::ProtectionLevel::ReadOnly && varPriv == privat)
if (bCheckReadOnly && varPriv == CBotVar::ProtectionLevel::ReadOnly)
return true;
if (varPriv == CBotVar::ProtectionLevel::Public) return false;

View File

@ -72,13 +72,12 @@ public:
* This function doesn't set the error flag itself.
*
* \param pStack Current compilation stack frame
* \param pPrev Class instance which variable to check is part of, or nullptr if not part of a class
* \param pPrev Class instance which variable to check is part of, or nullptr when compiler inserts 'this.' before
* \param pVar Variable to check
* \param privat CBotVar::ProtectionLevel::ReadOnly if requesting read-only access, anything else otherwise
* \param bCheckReadOnly True for operations that would modify the value of the variable
* \return true if pVar is inaccessible in the current context, false if access should be allowed
*/
static bool CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar,
CBotVar::ProtectionLevel privat = CBotVar::ProtectionLevel::Protected);
static bool CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar, bool bCheckReadOnly = false);
protected:
virtual const std::string GetDebugName() override { return "CBotFieldExpr"; }

View File

@ -46,7 +46,6 @@ CBotFunction::CBotFunction()
{
m_param = nullptr; // empty parameter list
m_block = nullptr; // the instruction block
m_next = nullptr; // functions can be chained
m_bPublic = false; // function not public
m_bExtern = false; // function not extern
m_pProg = nullptr;
@ -63,7 +62,6 @@ CBotFunction::~CBotFunction()
{
delete m_param; // empty parameter list
delete m_block; // the instruction block
delete m_next;
// remove public list if there is
if (m_bPublic)
@ -167,6 +165,7 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct
if ( IsOfType(p, ID_NOT) )
{
CBotToken d(std::string("~") + p->GetString());
d.SetPos(pp->GetStart(), p->GetEnd());
func->m_token = d;
}
@ -178,7 +177,11 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct
func->m_MasterClass = pp->GetString();
func->m_classToken = *pp;
CBotClass* pClass = CBotClass::Find(pp);
if ( pClass == nullptr ) goto bad;
if ( pClass == nullptr )
{
pStk->SetError(CBotErrNoClassName, pp);
goto bad;
}
// pp = p;
func->m_token = *p;
@ -186,6 +189,7 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct
}
func->m_openpar = *p;
delete func->m_param;
func->m_param = CBotDefParam::Compile(p, pStk );
func->m_closepar = *(p->GetPrev());
if (pStk->IsOk())
@ -224,6 +228,12 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct
func->m_closeblk = (p != nullptr && p->GetPrev() != nullptr) ? *(p->GetPrev()) : CBotToken();
if ( pStk->IsOk() )
{
if (!func->m_retTyp.Eq(CBotTypVoid) && !func->HasReturn())
{
int errPos = func->m_closeblk.GetStart();
pStk->ResetError(CBotErrNoReturn, errPos, errPos);
goto bad;
}
return pStack->ReturnFunc(func, pStk);
}
}
@ -270,6 +280,7 @@ CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClas
if ( IsOfType(p, ID_NOT) )
{
CBotToken d(std::string("~") + p->GetString());
d.SetPos(pp->GetStart(), p->GetEnd());
func->m_token = d;
}
@ -279,22 +290,47 @@ CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClas
if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class
{
func->m_MasterClass = pp->GetString();
CBotClass* pClass = CBotClass::Find(pp);
if ( pClass == nullptr )
{
pStk->SetError(CBotErrNotClass, pp);
goto bad;
}
// existence of the class is checked
// later in CBotFunction::Compile()
pp = p;
func->m_token = *p;
if (!IsOfType(p, TokenTypVar)) goto bad;
}
func->m_param = CBotDefParam::Compile(p, pStk );
CBotToken* openPar = p;
func->m_param = CBotDefParam::Compile(p, pStk); // compile parameters
if (pStk->IsOk() && pClass != nullptr) // method in a class
{
// check if a constructor has return type void
if (func->GetName() == pClass->GetName() && !func->m_retTyp.Eq(CBotTypVoid))
{
pp = &(func->m_retToken);
pStk->SetError(CBotErrFuncNotVoid, pp);
}
if (pStk->IsOk() && pp->GetString() == "~") // destructor
{
// check destructor name
if (func->GetName() != ("~" + pClass->GetName()))
pStk->SetError(CBotErrNoFunc, pp);
// confirm no parameters
if (pStk->IsOk() && func->m_param != nullptr)
pStk->SetError(CBotErrClosePar, openPar->GetNext());
// must return void
if (pStk->IsOk() && !func->m_retTyp.Eq(CBotTypVoid))
{
pp = &(func->m_retToken);
pStk->SetError(CBotErrFuncNotVoid, pp);
}
}
}
if (pStk->IsOk())
{
// looks if the function exists elsewhere
pp = &(func->m_token);
if (( pClass != nullptr || !pStack->CheckCall(pp, func->m_param)) &&
( pClass == nullptr || !pClass->CheckCall(pStack->GetProgram(), func->m_param, pp)) )
{
@ -334,9 +370,19 @@ bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
pile->SetProgram(m_pProg); // bases for routines
if ( pile->IfStep() ) return false;
if ( pile->GetState() == 0 )
{
if (m_param != nullptr)
{
// stack for parameters and default args
CBotStack* pile3b = pile->AddStack();
pile3b->SetState(1);
if ( !m_param->Execute(ppVars, pile) ) return false; // define parameters
pile3b->Delete(); // done with param stack
}
pile->IncState();
}
@ -369,8 +415,6 @@ bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
pile->IncState();
}
if ( pile->IfStep() ) return false;
if ( !m_block->Execute(pile) )
{
if ( pile->GetError() < 0 )
@ -399,7 +443,22 @@ void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInst
pile2->Delete();
}
m_param->RestoreState(pile2, true); // parameters
if ( pile->GetState() == 0 )
{
if (m_param != nullptr)
{
CBotStack* pile3b = pile2->RestoreStack();
if (pile3b != nullptr && pile3b->GetState() == 1)
m_param->RestoreState(pile2, true); // restore executing default arguments
else
m_param->RestoreState(pile2, false); // restore parameter IDs
}
return;
}
if (m_param != nullptr)
m_param->RestoreState(pile2, false); // restore parameter IDs
if ( !m_MasterClass.empty() )
{
@ -412,35 +471,26 @@ void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInst
}
////////////////////////////////////////////////////////////////////////////////
void CBotFunction::AddNext(CBotFunction* p)
CBotTypResult CBotFunction::CompileCall(const std::list<CBotFunction*>& localFunctionList, const std::string &name, CBotVar** ppVars, long &nIdent)
{
CBotFunction* pp = this;
while (pp->m_next != nullptr) pp = pp->m_next;
pp->m_next = p;
}
////////////////////////////////////////////////////////////////////////////////
CBotTypResult CBotFunction::CompileCall(const std::string& name, CBotVar** ppVars, long& nIdent)
{
nIdent = 0;
CBotTypResult type;
// CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
FindLocalOrPublic(nIdent, name, ppVars, type);
if (!FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type))
{
// Reset the identifier to "not found" value
nIdent = 0;
}
return type;
}
////////////////////////////////////////////////////////////////////////////////
CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& name, CBotVar** ppVars,
CBotTypResult& TypeOrError, bool bPublic)
CBotFunction* CBotFunction::FindLocalOrPublic(const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name,
CBotVar** ppVars, CBotTypResult &TypeOrError, bool bPublic)
{
TypeOrError.SetType(CBotErrUndefCall); // no routine of the name
CBotFunction* pt;
if ( nIdent )
{
if ( this != nullptr ) for ( pt = this ; pt != nullptr ; pt = pt->m_next )
for (CBotFunction* pt : localFunctionList)
{
if (pt->m_nFuncIdent == nIdent)
{
@ -464,9 +514,7 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
std::map<CBotFunction*, int> funcMap;
if ( this != nullptr )
{
for ( pt = this ; pt != nullptr ; pt = pt->m_next )
for (CBotFunction* pt : localFunctionList)
{
if ( pt->m_token.GetString() == name )
{
@ -475,8 +523,13 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
// parameters are compatible?
CBotDefParam* pv = pt->m_param; // expected list of parameters
CBotVar* pw = ppVars[i++]; // provided list parameter
while ( pv != nullptr && pw != nullptr)
while ( pv != nullptr && (pw != nullptr || pv->HasDefault()) )
{
if (pw == nullptr) // end of arguments
{
pv = pv->GetNext();
continue; // skip params with default values
}
CBotTypResult paramType = pv->GetTypResult();
CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
@ -521,7 +574,6 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
funcMap.insert( std::pair<CBotFunction*, int>(pt, alpha) );
}
}
}
if ( bPublic )
{
@ -534,8 +586,13 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
// parameters sont-ils compatibles ?
CBotDefParam* pv = pt->m_param; // list of expected parameters
CBotVar* pw = ppVars[i++]; // list of provided parameters
while ( pv != nullptr && pw != nullptr)
while ( pv != nullptr && (pw != nullptr || pv->HasDefault()) )
{
if (pw == nullptr) // end of arguments
{
pv = pv->GetNext();
continue; // skip params with default values
}
CBotTypResult paramType = pv->GetTypResult();
CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
@ -610,12 +667,13 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
}
////////////////////////////////////////////////////////////////////////////////
int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken)
int CBotFunction::DoCall(CBotProgram* program, const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name,
CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken)
{
CBotTypResult type;
CBotFunction* pt = nullptr;
pt = FindLocalOrPublic(nIdent, name, ppVars, type);
pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type);
if ( pt != nullptr )
{
@ -632,9 +690,12 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars
if ( pStk1->GetState() == 0 )
{
if ( !pt->m_MasterClass.empty() )
// stack for parameters and default args
CBotStack* pStk3b = pStk3->AddStack();
if (pStk3b->GetState() == 0 && !pt->m_MasterClass.empty())
{
CBotVar* pInstance = m_pProg->m_thisVar;
CBotVar* pInstance = program->m_thisVar;
// make "this" known
CBotVar* pThis ;
if ( pInstance == nullptr )
@ -658,10 +719,21 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars
pThis->SetUniqNum(-2);
pStk1->AddVar(pThis);
}
pStk3b->SetState(1); // set 'this' was created
// initializes the variables as parameters
pt->m_param->Execute(ppVars, pStk3); // cannot be interrupted
if (pt->m_param != nullptr)
{
if (!pt->m_param->Execute(ppVars, pStk3)) // interupt here
{
if (!pStk3->IsOk() && pt->m_pProg != program)
{
pStk3->SetPosError(pToken); // indicates the error on the procedure call
}
return false;
}
}
pStk3b->Delete(); // done with param stack
pStk1->IncState();
}
@ -670,7 +742,7 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars
if ( !pStk3->GetRetVar( // puts the result on the stack
pt->m_block->Execute(pStk3) )) // GetRetVar said if it is interrupted
{
if ( !pStk3->IsOk() && pt->m_pProg != m_pProg )
if ( !pStk3->IsOk() && pt->m_pProg != program )
{
pStk3->SetPosError(pToken); // indicates the error on the procedure call
}
@ -683,7 +755,8 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars
}
////////////////////////////////////////////////////////////////////////////////
void CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar** ppVars, CBotStack* pStack)
void CBotFunction::RestoreCall(const std::list<CBotFunction*>& localFunctionList,
long &nIdent, const std::string &name, CBotVar** ppVars, CBotStack* pStack)
{
CBotTypResult type;
CBotFunction* pt = nullptr;
@ -692,7 +765,7 @@ void CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar**
// search function to return the ok identifier
pt = FindLocalOrPublic(nIdent, name, ppVars, type);
pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type);
if ( pt != nullptr )
{
@ -729,24 +802,33 @@ void CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar**
if ( pStk1->GetState() == 0 )
{
pt->m_param->RestoreState(pStk3, true);
if (pt->m_param != nullptr)
{
CBotStack* pStk3b = pStk3->RestoreStack();
if (pStk3b != nullptr && pStk3b->GetState() == 1)
pt->m_param->RestoreState(pStk3, true); // restore executing default arguments
else
pt->m_param->RestoreState(pStk3, false); // restore parameter IDs
}
return;
}
// initializes the variables as parameters
pt->m_param->RestoreState(pStk3, false);
if (pt->m_param != nullptr)
pt->m_param->RestoreState(pStk3, false); // restore parameter IDs
pt->m_block->RestoreState(pStk3, true);
}
}
////////////////////////////////////////////////////////////////////////////////
int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack,
CBotToken* pToken, CBotClass* pClass)
int CBotFunction::DoCall(const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis,
CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass)
{
CBotTypResult type;
CBotProgram* pProgCurrent = pStack->GetProgram();
CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type, false);
CBotFunction* pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type, false);
if ( pt != nullptr )
{
@ -761,6 +843,11 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar* pThis,
// preparing parameters on the stack
if ( pStk->GetState() == 0 )
{
// stack for parameters and default args
CBotStack* pStk3b = pStk3->AddStack();
if (pStk3b->GetState() == 0)
{
// sets the variable "this" on the stack
CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer);
@ -777,8 +864,22 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar* pThis,
psuper->SetUniqNum(-3); // special value
pStk->AddVar(psuper);
}
}
pStk3b->SetState(1); // set 'this' was created
// initializes the variables as parameters
pt->m_param->Execute(ppVars, pStk3); // cannot be interrupted
if (pt->m_param != nullptr)
{
if (!pt->m_param->Execute(ppVars, pStk3)) // interupt here
{
if (!pStk3->IsOk() && pt->m_pProg != pProgCurrent)
{
pStk3->SetPosError(pToken); // indicates the error on the procedure call
}
return false;
}
}
pStk3b->Delete(); // done with param stack
pStk->IncState();
}
@ -822,11 +923,11 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar* pThis,
}
////////////////////////////////////////////////////////////////////////////////
bool CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar* pThis, CBotVar** ppVars,
CBotStack* pStack, CBotClass* pClass)
bool CBotFunction::RestoreCall(const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis,
CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass)
{
CBotTypResult type;
CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
CBotFunction* pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type);
if ( pt != nullptr )
{
@ -846,7 +947,21 @@ bool CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar* p
CBotStack* pStk3 = pStk->RestoreStack(nullptr); // to set parameters passed
if ( pStk3 == nullptr ) return true;
pt->m_param->RestoreState(pStk3, true); // parameters
if ( pStk->GetState() == 0 )
{
if (pt->m_param != nullptr)
{
CBotStack* pStk3b = pStk3->RestoreStack();
if (pStk3b != nullptr && pStk3b->GetState() == 1)
pt->m_param->RestoreState(pStk3, true); // restore executing default arguments
else
pt->m_param->RestoreState(pStk3, false); // restore parameter IDs
}
return true;
}
if (pt->m_param != nullptr)
pt->m_param->RestoreState(pStk3, false); // restore parameter IDs
if ( pStk->GetState() > 1 && // latching is effective?
pt->m_bSynchro )
@ -903,18 +1018,18 @@ std::string CBotFunction::GetParams()
return params;
}
////////////////////////////////////////////////////////////////////////////////
CBotFunction* CBotFunction::Next()
{
return m_next;
}
////////////////////////////////////////////////////////////////////////////////
void CBotFunction::AddPublic(CBotFunction* func)
{
m_publicFunctions.insert(func);
}
bool CBotFunction::HasReturn()
{
if (m_block != nullptr) return m_block->HasReturn();
return false;
}
std::string CBotFunction::GetDebugData()
{
std::stringstream ss;

View File

@ -60,11 +60,16 @@ public:
bool bLocal = true);
/*!
* \brief Compile1 Pre-compile a new function.
* \param p
* \param pStack
* \param pClass
* \return
* \brief Pre-compile a new function
* \param p[in, out] Pointer to first token of the function, will be updated to point to first token after the function definition
* \param pStack Compile stack
* \param pClass If this is a class method, pointer to class this function is part of, otherwise nullptr
*
* This function is used to find the beginning and end of function definition.
*
* If any errors in the code are detected, this function will set the error on compile stack and return nullptr.
*
* \return Precompiled function, or nullptr in case of error
*/
static CBotFunction* Compile1(CBotToken* &p,
CBotCStack* pStack,
@ -81,6 +86,8 @@ public:
CBotStack* &pj,
CBotVar* pInstance = nullptr);
using CBotInstr::Execute;
/*!
* \brief RestoreState
* \param ppVars
@ -91,40 +98,46 @@ public:
CBotStack* &pj,
CBotVar* pInstance = nullptr);
/*!
* \brief AddNext
* \param p
*/
void AddNext(CBotFunction* p);
using CBotInstr::RestoreState;
/*!
* \brief CompileCall
* \param name
* \param ppVars
* \param nIdent
* \return
* \brief Compile a function call
*
* See FindLocalOrPublic for more detailed explanation
*
* \param localFunctionList Linked list of local functions to search in, can be null
* \param name Name of the function
* \param ppVars List of function arguments
* \param nIdent[in, out] Unique identifier of the function
* \return Type returned by the function or error code
* \see FindLocalOrPublic
*/
CBotTypResult CompileCall(const std::string& name,
CBotVar** ppVars,
long& nIdent);
static CBotTypResult CompileCall(const std::list<CBotFunction*>& localFunctionList,
const std::string &name, CBotVar** ppVars, long &nIdent);
/*!
* \brief FindLocalOrPublic Is a function according to its unique identifier
* if the identifier is not found, looking by name and parameters.
* \param nIdent
* \param name
* \param ppVars
* \param TypeOrError
* \param bPublic
* \return
* \brief Finds a local or public function
*
* <p>Finds a local or (if bPublic is true) public function to call
*
* <p>First, it looks for a function according to its unique identifier.<br>
* If the identifier is not found, looks by name and parameters.
*
* \param localFunctionList Linked list of local functions to search in, can be null
* \param nIdent[in, out] Unique identifier of the function
* \param name Name of the function
* \param ppVars List of function arguments
* \param TypeOrError Type returned by the function or error code
* \param bPublic Whether to look in public functions or not
* \return Pointer to found CBotFunction instance, or nullptr in case of no match or ambiguity (see TypeOrError for error code)
*/
CBotFunction* FindLocalOrPublic(long& nIdent, const std::string& name,
CBotVar** ppVars,
CBotTypResult& TypeOrError,
bool bPublic = true);
static CBotFunction* FindLocalOrPublic(const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name,
CBotVar** ppVars, CBotTypResult &TypeOrError, bool bPublic = true);
/*!
* \brief DoCall Fait un appel à une fonction.
* \param program
* \param localFunctionList
* \param nIdent
* \param name
* \param ppVars
@ -133,27 +146,24 @@ public:
* \return
*/
int DoCall(long& nIdent,
const std::string& name,
CBotVar** ppVars,
CBotStack* pStack,
CBotToken* pToken);
static int DoCall(CBotProgram* program, const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name,
CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken);
/*!
* \brief RestoreCall
* \param localFunctionList
* \param nIdent
* \param name
* \param ppVars
* \param pStack
*/
void RestoreCall(long& nIdent,
const std::string& name,
CBotVar** ppVars,
CBotStack* pStack);
static void RestoreCall(const std::list<CBotFunction*>& localFunctionList,
long &nIdent, const std::string &name, CBotVar** ppVars, CBotStack* pStack);
/*!
* \brief DoCall Makes call of a method note: this is already on the stack,
* the pointer pThis is just to simplify.
* \brief DoCall Makes call of a method
* note: this is already on the stack, the pointer pThis is just to simplify.
* \param localFunctionList
* \param nIdent
* \param name
* \param pThis
@ -163,16 +173,12 @@ public:
* \param pClass
* \return
*/
int DoCall(long& nIdent,
const std::string& name,
CBotVar* pThis,
CBotVar** ppVars,
CBotStack* pStack,
CBotToken* pToken,
CBotClass* pClass);
static int DoCall(const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis,
CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass);
/*!
* \brief RestoreCall
* \param localFunctionList
* \param nIdent
* \param name
* \param pThis
@ -181,12 +187,8 @@ public:
* \param pClass
* \return Returns true if the method call was restored.
*/
bool RestoreCall(long& nIdent,
const std::string& name,
CBotVar* pThis,
CBotVar** ppVars,
CBotStack* pStack,
CBotClass* pClass);
static bool RestoreCall(const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis,
CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass);
/*!
* \brief CheckParam See if the "signature" of parameters is identical.
@ -225,12 +227,6 @@ public:
*/
bool IsExtern();
/*!
* \brief Next
* \return
*/
CBotFunction* Next();
/*!
* \brief GetPosition
* \param start
@ -243,6 +239,12 @@ public:
CBotGet modestart,
CBotGet modestop);
/*!
* \brief Check if the function has a return statment that will execute.
* \return true if a return statment was found.
*/
bool HasReturn() override;
protected:
virtual const std::string GetDebugName() override { return "CBotFunction"; }
virtual std::string GetDebugData() override;
@ -258,7 +260,6 @@ private:
CBotDefParam* m_param;
//! The instruction block.
CBotInstr* m_block;
CBotFunction* m_next;
//! If returns CBotTypClass.
CBotToken m_retToken;
//! Complete type of the result.

View File

@ -163,6 +163,15 @@ void CBotIf :: RestoreState(CBotStack* &pj, bool bMain)
}
}
bool CBotIf::HasReturn()
{
if (m_block != nullptr && m_blockElse != nullptr)
{
if (m_block->HasReturn() && m_blockElse->HasReturn()) return true;
}
return CBotInstr::HasReturn(); // check next block or instruction
}
std::map<std::string, CBotInstr*> CBotIf::GetDebugLinks()
{
auto links = CBotInstr::GetDebugLinks();

View File

@ -56,6 +56,14 @@ public:
*/
void RestoreState(CBotStack* &pj, bool bMain) override;
/**
* \brief Check 'if' and 'else' for return statements.
* Returns true when 'if' and 'else' have return statements,
* if not, the next block or instruction is checked.
* \return true if a return statement is found.
*/
bool HasReturn() override;
protected:
virtual const std::string GetDebugName() override { return "CBotIf"; }
virtual std::map<std::string, CBotInstr*> GetDebugLinks() override;

View File

@ -359,6 +359,12 @@ CBotInstr* CBotInstr::CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypRes
return nullptr;
}
bool CBotInstr::HasReturn()
{
if (m_next != nullptr) return m_next->HasReturn();
return false; // end of the list
}
std::map<std::string, CBotInstr*> CBotInstr::GetDebugLinks()
{
return {

View File

@ -281,6 +281,12 @@ public:
*/
static bool ChkLvl(const std::string& label, int type);
/**
* \brief Check a list of instructions for a return statement.
* \return true if a return statement was found.
*/
virtual bool HasReturn();
protected:
friend class CBotDebug;
/**

View File

@ -36,6 +36,7 @@ namespace CBot
CBotInstrCall::CBotInstrCall()
{
m_parameters = nullptr;
m_exprRetVar = nullptr;
m_nFuncIdent = 0;
}
@ -43,6 +44,7 @@ CBotInstrCall::CBotInstrCall()
CBotInstrCall::~CBotInstrCall()
{
delete m_parameters;
delete m_exprRetVar;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -36,6 +36,7 @@ namespace CBot
CBotInstrMethode::CBotInstrMethode()
{
m_parameters = nullptr;
m_exprRetVar = nullptr;
m_MethodeIdent = 0;
}
@ -43,6 +44,7 @@ CBotInstrMethode::CBotInstrMethode()
CBotInstrMethode::~CBotInstrMethode()
{
delete m_parameters;
delete m_exprRetVar;
}
////////////////////////////////////////////////////////////////////////////////
@ -67,8 +69,7 @@ CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar*
inst->m_thisIdent = var->GetUniqNum();
CBotClass* pClass = var->GetClass(); // pointer to the class
inst->m_className = pClass->GetName(); // name of the class
CBotTypResult r = pClass->CompileMethode(inst->m_methodName, var, ppVars,
pStack, inst->m_MethodeIdent);
CBotTypResult r = pClass->CompileMethode(pp, var, ppVars, pStack, inst->m_MethodeIdent);
delete pStack->TokenStack(); // release parameters on the stack
inst->m_typRes = r;
@ -176,18 +177,7 @@ bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* pre
else
pClass = pThis->GetClass();
CBotVar* pResult = nullptr;
if (m_typRes.GetType() > 0) pResult = CBotVar::Create("", m_typRes);
if (m_typRes.Eq(CBotTypClass))
{
pResult->SetClass(m_typRes.GetClass());
}
CBotVar* pRes = pResult;
if ( !pClass->ExecuteMethode(m_MethodeIdent, m_methodName,
pThis, ppVars,
pResult, pile2, GetToken())) return false;
if (pRes != pResult) delete pRes;
if ( !pClass->ExecuteMethode(m_MethodeIdent, pThis, ppVars, m_typRes, pile2, GetToken())) return false;
if (m_exprRetVar != nullptr) // .func().member
{
@ -264,8 +254,7 @@ void CBotInstrMethode::RestoreStateVar(CBotStack* &pile, bool bMain)
// CBotVar* pRes = pResult;
pClass->RestoreMethode(m_MethodeIdent, m_methodName,
pThis, ppVars, pile2);
pClass->RestoreMethode(m_MethodeIdent, &m_token, pThis, ppVars, pile2);
}
////////////////////////////////////////////////////////////////////////////////
@ -316,24 +305,12 @@ bool CBotInstrMethode::Execute(CBotStack* &pj)
else
pClass = pThis->GetClass();
CBotVar* pResult = nullptr;
if (m_typRes.GetType()>0) pResult = CBotVar::Create("", m_typRes);
if (m_typRes.Eq(CBotTypClass))
{
pResult->SetClass(m_typRes.GetClass());
}
CBotVar* pRes = pResult;
if ( !pClass->ExecuteMethode(m_MethodeIdent, m_methodName,
pThis, ppVars,
pResult, pile2, GetToken())) return false; // interupted
if ( !pClass->ExecuteMethode(m_MethodeIdent, pThis, ppVars, m_typRes, pile2, GetToken())) return false; // interupted
// set the new value of this in place of the old variable
CBotVar* old = pile1->FindVar(m_token, false);
old->Copy(pThis, false);
if (pRes != pResult) delete pRes;
return pj->Return(pile2); // release the entire stack
}

View File

@ -64,7 +64,7 @@ CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack)
inst->m_nIdent = var->GetUniqNum();
if (inst->m_nIdent > 0 && inst->m_nIdent < 9000)
{
if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, CBotVar::ProtectionLevel::ReadOnly))
if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, true))
{
pStk->SetError(CBotErrPrivate, p);
goto err;
@ -128,8 +128,7 @@ CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack)
var = var->GetItem(p->GetString()); // get item correspondent
if (var != nullptr)
{
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var,
CBotVar::ProtectionLevel::ReadOnly))
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, true))
{
pStk->SetError(CBotErrPrivate, pp);
goto err;

View File

@ -61,6 +61,8 @@ public:
*/
bool Execute(CBotStack* &pStack, CBotStack* array);
using CBotInstr::Execute;
/*!
* \brief ExecuteVar Fetch a variable during compilation.
* \param pVar
@ -69,6 +71,8 @@ public:
*/
bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) override;
using CBotInstr::ExecuteVar;
/*!
* \brief ExecuteVar Fetch the variable at runtume.
* \param pVar

View File

@ -52,7 +52,7 @@ CBotInstr* CBotListInstr::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal
if (IsOfType(p, ID_SEP)) continue; // empty statement ignored
if (p->GetType() == ID_CLBLK) break;
if (IsOfType(p, 0))
if (p->GetType() == TokenTypNone)
{
pStack->SetError(CBotErrCloseBlock, p->GetStart());
delete inst;
@ -117,6 +117,12 @@ void CBotListInstr::RestoreState(CBotStack* &pj, bool bMain)
if (p != nullptr) p->RestoreState(pile, true);
}
bool CBotListInstr::HasReturn()
{
if (m_instr != nullptr && m_instr->HasReturn()) return true;
return CBotInstr::HasReturn(); // check next block or instruction
}
std::map<std::string, CBotInstr*> CBotListInstr::GetDebugLinks()
{
auto links = CBotInstr::GetDebugLinks();

View File

@ -56,6 +56,13 @@ public:
*/
void RestoreState(CBotStack* &pj, bool bMain) override;
/**
* \brief Check this block of instructions for a return statement.
* If not found, the next block or instruction is checked.
* \return true if a return statement was found.
*/
bool HasReturn() override;
protected:
virtual const std::string GetDebugName() override { return "CBotListInstr"; }
virtual std::map<std::string, CBotInstr*> GetDebugLinks() override;

View File

@ -36,12 +36,15 @@ namespace CBot
CBotNew::CBotNew()
{
m_parameters = nullptr;
m_exprRetVar = nullptr;
m_nMethodeIdent = 0;
}
////////////////////////////////////////////////////////////////////////////////
CBotNew::~CBotNew()
{
delete m_parameters;
delete m_exprRetVar;
}
////////////////////////////////////////////////////////////////////////////////
@ -83,7 +86,7 @@ CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack)
if (!pStk->IsOk()) goto error;
// constructor exist?
CBotTypResult r = pClass->CompileMethode(pClass->GetName(), pVar, ppVars, pStk, inst->m_nMethodeIdent);
CBotTypResult r = pClass->CompileMethode(&inst->m_vartoken, pVar, ppVars, pStk, inst->m_nMethodeIdent);
delete pStk->TokenStack(); // release extra stack
int typ = r.GetType();
@ -197,12 +200,7 @@ bool CBotNew::Execute(CBotStack* &pj)
}
ppVars[i] = nullptr;
// create a variable for the result
CBotVar* pResult = nullptr; // constructos still void
if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GetName(),
pThis, ppVars,
pResult, pile2, GetToken())) return false; // interrupt
if ( !pClass->ExecuteMethode(m_nMethodeIdent, pThis, ppVars, CBotTypResult(CBotTypVoid), pile2, &m_vartoken)) return false; // interrupt
pThis->ConstructorSet(); // indicates that the constructor has been called
}
@ -284,8 +282,7 @@ void CBotNew::RestoreState(CBotStack* &pj, bool bMain)
}
ppVars[i] = nullptr;
pClass->RestoreMethode(m_nMethodeIdent, m_vartoken.GetString(), pThis,
ppVars, pile2) ; // interrupt here!
pClass->RestoreMethode(m_nMethodeIdent, &m_vartoken, pThis, ppVars, pile2); // interrupt here!
}
}

View File

@ -90,17 +90,16 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
// post incremented or decremented?
if (IsOfType(p, ID_INC, ID_DEC))
{
// recompile the variable for read-only
delete inst;
p = pvar;
inst = CBotExprVar::Compile(p, pStk, true);
if (pStk->GetType() >= CBotTypBoolean)
{
pStk->SetError(CBotErrBadType1, pp);
delete inst;
return pStack->Return(nullptr, pStk);
}
// recompile the variable for read-only
delete inst;
p = pvar;
inst = CBotExprVar::Compile(p, pStk, CBotVar::ProtectionLevel::ReadOnly);
p = p->GetNext();
CBotPostIncExpr* i = new CBotPostIncExpr();
@ -115,26 +114,39 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
CBotToken* pp = p;
if (IsOfType(p, ID_INC, ID_DEC))
{
CBotPreIncExpr* i = new CBotPreIncExpr();
i->SetToken(pp);
if (p->GetType() == TokenTypVar)
{
if (nullptr != (i->m_instr = CBotExprVar::Compile(p, pStk, CBotVar::ProtectionLevel::ReadOnly)))
if (nullptr != (inst = CBotExprVar::Compile(p, pStk, true)))
{
if (pStk->GetType() >= CBotTypBoolean)
if (pStk->GetType() < CBotTypBoolean) // a number ?
{
pStk->SetError(CBotErrBadType1, pp);
delete inst;
return pStack->Return(nullptr, pStk);
}
CBotPreIncExpr* i = new CBotPreIncExpr();
i->SetToken(pp);
i->m_instr = inst;
return pStack->Return(i, pStk);
}
delete i;
delete inst;
}
}
pStk->SetError(CBotErrBadType1, pp);
return pStack->Return(nullptr, pStk);
}
return CBotParExpr::CompileLitExpr(p, pStack);
}
////////////////////////////////////////////////////////////////////////////////
CBotInstr* CBotParExpr::CompileLitExpr(CBotToken* &p, CBotCStack* pStack)
{
CBotCStack* pStk = pStack->TokenStack();
CBotToken* pp = p;
// is this a unary operation?
CBotInstr* inst = CBotExprUnaire::Compile(p, pStk, true);
if (inst != nullptr || !pStk->IsOk())
return pStack->Return(inst, pStk);
// is it a number or DefineNum?
if (p->GetType() == TokenTypNum ||
p->GetType() == TokenTypDef )

View File

@ -54,6 +54,14 @@ public:
*/
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
/*!
* \brief Compile a literal expression ("string", number, true, false, null, nan, new)
* \param p[in, out] Pointer to first token of the expression, will be updated to point to first token after the expression
* \param pStack Current compilation stack frame
* \return The compiled instruction or nullptr on error
*/
static CBotInstr* CompileLitExpr(CBotToken* &p, CBotCStack* pStack);
private:
CBotParExpr() = delete;
CBotParExpr(const CBotParExpr&) = delete;

View File

@ -111,6 +111,11 @@ void CBotReturn::RestoreState(CBotStack* &pj, bool bMain)
}
}
bool CBotReturn::HasReturn()
{
return true;
}
std::map<std::string, CBotInstr*> CBotReturn::GetDebugLinks()
{
auto links = CBotInstr::GetDebugLinks();

View File

@ -55,6 +55,12 @@ public:
*/
void RestoreState(CBotStack* &pj, bool bMain) override;
/*!
* \brief Always returns true.
* \return true to signal a return statment has been found.
*/
bool HasReturn() override;
protected:
virtual const std::string GetDebugName() override { return "CBotReturn"; }
virtual std::map<std::string, CBotInstr*> GetDebugLinks() override;

View File

@ -30,6 +30,8 @@
#include "CBot/stdlib/stdlib.h"
#include <algorithm>
namespace CBot
{
@ -47,27 +49,30 @@ CBotProgram::CBotProgram(CBotVar* thisVar)
CBotProgram::~CBotProgram()
{
// delete m_classes;
if (m_classes != nullptr) m_classes->Purge();
m_classes = nullptr;
for (CBotClass* c : m_classes)
c->Purge();
m_classes.clear();
CBotClass::FreeLock(this);
delete m_functions;
if (m_stack != nullptr) m_stack->Delete();
for (CBotFunction* f : m_functions) delete f;
m_functions.clear();
}
bool CBotProgram::Compile(const std::string& program, std::vector<std::string>& functions, void* pUser)
bool CBotProgram::Compile(const std::string& program, std::vector<std::string>& externFunctions, void* pUser)
{
// Cleanup the previously compiled program
Stop();
// delete m_classes;
if (m_classes != nullptr) m_classes->Purge(); // purge the old definitions of classes
for (CBotClass* c : m_classes)
c->Purge(); // purge the old definitions of classes
// but without destroying the object
m_classes = nullptr;
delete m_functions; m_functions = nullptr;
functions.clear();
m_classes.clear();
for (CBotFunction* f : m_functions) delete f;
m_functions.clear();
externFunctions.clear();
m_error = CBotNoErr;
// Step 1. Process the code into tokens
@ -88,15 +93,15 @@ bool CBotProgram::Compile(const std::string& program, std::vector<std::string>&
if ( p->GetType() == ID_CLASS ||
( p->GetType() == ID_PUBLIC && p->GetNext()->GetType() == ID_CLASS ))
{
CBotClass* nxt = CBotClass::Compile1(p, pStack.get());
if (m_classes == nullptr ) m_classes = nxt;
else m_classes->AddNext(nxt);
CBotClass* newclass = CBotClass::Compile1(p, pStack.get());
if (newclass != nullptr)
m_classes.push_back(newclass);
}
else
{
CBotFunction* next = CBotFunction::Compile1(p, pStack.get(), nullptr);
if (m_functions == nullptr ) m_functions = next;
else m_functions->AddNext(next);
CBotFunction* newfunc = CBotFunction::Compile1(p, pStack.get(), nullptr);
if (newfunc != nullptr)
m_functions.push_back(newfunc);
}
}
@ -106,17 +111,14 @@ bool CBotProgram::Compile(const std::string& program, std::vector<std::string>&
if ( !pStack->IsOk() )
{
m_error = pStack->GetError(m_errorStart, m_errorEnd);
delete m_functions;
m_functions = nullptr;
for (CBotFunction* f : m_functions) delete f;
m_functions.clear();
return false;
}
// Step 3. Real compilation
// CBotFunction* temp = nullptr;
CBotFunction* next = m_functions; // rewind the list
std::list<CBotFunction*>::iterator next = m_functions.begin();
p = tokens.get()->GetNext(); // returns to the beginning
while ( pStack->IsOk() && p != nullptr && p->GetType() != 0 )
{
if ( IsOfType(p, ID_SEP) ) continue; // semicolons lurking
@ -128,43 +130,35 @@ bool CBotProgram::Compile(const std::string& program, std::vector<std::string>&
}
else
{
CBotFunction::Compile(p, pStack.get(), next);
if (next->IsExtern()) functions.push_back(next->GetName()/* + next->GetParams()*/);
if (next->IsPublic()) CBotFunction::AddPublic(next);
next->m_pProg = this; // keeps pointers to the module
next = next->Next();
CBotFunction::Compile(p, pStack.get(), *next);
if ((*next)->IsExtern()) externFunctions.push_back((*next)->GetName()/* + next->GetParams()*/);
if ((*next)->IsPublic()) CBotFunction::AddPublic(*next);
(*next)->m_pProg = this; // keeps pointers to the module
++next;
}
}
// delete m_Prog; // the list of first pass
// m_Prog = temp; // list of the second pass
if ( !pStack->IsOk() )
{
m_error = pStack->GetError(m_errorStart, m_errorEnd);
delete m_functions;
m_functions = nullptr;
for (CBotFunction* f : m_functions) delete f;
m_functions.clear();
}
return (m_functions != nullptr);
return !m_functions.empty();
}
bool CBotProgram::Start(const std::string& name)
{
Stop();
m_entryPoint = m_functions;
while (m_entryPoint != nullptr)
{
if (m_entryPoint->GetName() == name ) break;
m_entryPoint = m_entryPoint->m_next;
}
if (m_entryPoint == nullptr)
auto it = std::find_if(m_functions.begin(), m_functions.end(), [&name](CBotFunction* x) { return x->GetName() == name; });
if (it == m_functions.end())
{
m_error = CBotErrNoRun;
return false;
}
m_entryPoint = *it;
m_stack = CBotStack::AllocateStack();
m_stack->SetProgram(this);
@ -174,16 +168,10 @@ bool CBotProgram::Start(const std::string& name)
bool CBotProgram::GetPosition(const std::string& name, int& start, int& stop, CBotGet modestart, CBotGet modestop)
{
CBotFunction* p = m_functions;
while (p != nullptr)
{
if ( p->GetName() == name ) break;
p = p->m_next;
}
auto it = std::find_if(m_functions.begin(), m_functions.end(), [&name](CBotFunction* x) { return x->GetName() == name; });
if (it == m_functions.end()) return false;
if ( p == nullptr ) return false;
p->GetPosition(start, stop, modestart, modestop);
(*it)->GetPosition(start, stop, modestart, modestop);
return true;
}
@ -212,16 +200,16 @@ bool CBotProgram::Run(void* pUser, int timer)
}
// completed on a mistake?
if (!ok && !m_stack->IsOk())
if (ok || !m_stack->IsOk())
{
m_error = m_stack->GetError(m_errorStart, m_errorEnd);
m_stack->Delete();
m_stack = nullptr;
CBotClass::FreeLock(this);
m_entryPoint = nullptr;
return true; // execution is finished!
}
if ( ok ) m_entryPoint = nullptr; // more function in execution
return ok;
}
@ -288,11 +276,21 @@ bool CBotProgram::GetError(CBotError& code, int& start, int& end, CBotProgram*&
}
////////////////////////////////////////////////////////////////////////////////
CBotFunction* CBotProgram::GetFunctions()
const std::list<CBotFunction*>& CBotProgram::GetFunctions()
{
return m_functions;
}
bool CBotProgram::ClassExists(std::string name)
{
for (CBotClass* p : m_classes)
{
if ( p->GetName() == name ) return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
CBotTypResult cSizeOf( CBotVar* &pVar, void* pUser )
{
@ -304,7 +302,7 @@ CBotTypResult cSizeOf( CBotVar* &pVar, void* pUser )
bool rSizeOf( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
{
if ( pVar == nullptr ) return CBotErrLowParam;
if ( pVar == nullptr ) { ex = CBotErrLowParam; return true; }
int i = 0;
pVar = pVar->GetItemList();
@ -375,8 +373,7 @@ bool CBotProgram::RestoreState(FILE* pf)
}
// retrieves the stack from the memory
// uses a nullptr pointer (m_stack) but it's ok like that
// TODO: no it's not okay like that! but it looks like it doesn't get optimized out at least ~krzys_h
m_stack = CBotStack::AllocateStack();
if (!m_stack->RestoreState(pf, m_stack)) return false;
m_stack->SetProgram(this); // bases for routines

View File

@ -23,6 +23,7 @@
#include "CBot/CBotEnums.h"
#include <vector>
#include <list>
namespace CBot
{
@ -124,12 +125,12 @@ public:
* 3. Second pass - compiling definitions of all functions and classes
*
* \param program Code to compile
* \param[out] functions Returns the names of functions declared as extern
* \param[out] externFunctions Returns the names of functions declared as extern
* \param pUser Optional pointer to be passed to compile function (see AddFunction())
* \return true if compilation is successful, false if an compilation error occurs
* \see GetError() to retrieve the error
*/
bool Compile(const std::string& program, std::vector<std::string>& functions, void* pUser = nullptr);
bool Compile(const std::string& program, std::vector<std::string>& externFunctions, void* pUser = nullptr);
/**
* \brief Returns the last error
@ -328,9 +329,15 @@ public:
*
* This list includes all the functions (not only extern)
*
* \return Linked list of CBotFunction instances
* \return List of CBotFunction instances
*/
CBotFunction* GetFunctions();
const std::list<CBotFunction*>& GetFunctions();
/**
* \brief Check if class with that name was created in this program
* \return True if class was defined in this program, otherwise, false
*/
bool ClassExists(std::string name);
/**
* \brief Returns static list of all registered external calls
@ -341,11 +348,11 @@ private:
//! All external calls
static CBotExternalCallList* m_externalCalls;
//! All user-defined functions
CBotFunction* m_functions = nullptr;
std::list<CBotFunction*> m_functions{};
//! The entry point function
CBotFunction* m_entryPoint = nullptr;
//! Classes defined in this program
CBotClass* m_classes = nullptr;
std::list<CBotClass*> m_classes{};
//! Execution stack
CBotStack* m_stack = nullptr;
//! "this" variable

View File

@ -82,8 +82,6 @@ CBotStack* CBotStack::AllocateStack()
////////////////////////////////////////////////////////////////////////////////
void CBotStack::Delete()
{
assert ( this != nullptr );
if (m_next != nullptr) m_next->Delete();
if (m_next2 != nullptr) m_next2->Delete();
@ -192,8 +190,18 @@ bool CBotStack::Return(CBotStack* pfils)
m_var = pfils->m_var; // result transmitted
pfils->m_var = nullptr; // not to destroy the variable
if (m_next != nullptr) m_next->Delete();m_next = nullptr; // releases the stack above
if (m_next2 != nullptr) m_next2->Delete();m_next2 = nullptr; // also the second stack (catch)
if (m_next != nullptr)
{
// releases the stack above
m_next->Delete();
m_next = nullptr;
}
if (m_next2 != nullptr)
{
// also the second stack (catch)
m_next2->Delete();
m_next2 = nullptr;
}
return IsOk(); // interrupted if error
}
@ -260,7 +268,7 @@ bool CBotStack::IfStep()
bool CBotStack::BreakReturn(CBotStack* pfils, const std::string& name)
{
if ( m_error>=0 ) return false; // normal output
if ( m_error==-3 ) return false; // normal output (return current)
if ( m_error==CBotError(-3) ) return false; // normal output (return current)
if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name))
return false; // it's not for me
@ -273,7 +281,7 @@ bool CBotStack::BreakReturn(CBotStack* pfils, const std::string& name)
////////////////////////////////////////////////////////////////////////////////
bool CBotStack::IfContinue(int state, const std::string& name)
{
if ( m_error != -2 ) return false;
if ( m_error != CBotError(-2) ) return false;
if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name))
return false; // it's not for me
@ -301,7 +309,7 @@ void CBotStack::SetBreak(int val, const std::string& name)
////////////////////////////////////////////////////////////////////////////////
bool CBotStack::GetRetVar(bool bRet)
{
if (m_error == -3)
if (m_error == CBotError(-3))
{
if ( m_var ) delete m_var;
m_var = m_retvar;
@ -568,7 +576,7 @@ bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, con
res = m_prog->GetExternalCalls()->DoCall(nullptr, nullptr, ppVar, this, rettype);
if (res >= 0) return res;
res = m_prog->GetFunctions()->DoCall(nIdent, "", ppVar, this, token );
res = CBotFunction::DoCall(m_prog, m_prog->GetFunctions(), nIdent, "", ppVar, this, token);
if (res >= 0) return res;
// if not found (recompile?) seeks by name
@ -577,7 +585,7 @@ bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, con
res = m_prog->GetExternalCalls()->DoCall(token, nullptr, ppVar, this, rettype);
if (res >= 0) return res;
res = m_prog->GetFunctions()->DoCall(nIdent, token->GetString(), ppVar, this, token );
res = CBotFunction::DoCall(m_prog, m_prog->GetFunctions(), nIdent, token->GetString(), ppVar, this, token);
if (res >= 0) return res;
SetError(CBotErrUndefFunc, token);
@ -592,7 +600,7 @@ void CBotStack::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar)
if (m_prog->GetExternalCalls()->RestoreCall(token, nullptr, ppVar, this))
return;
m_prog->GetFunctions()->RestoreCall(nIdent, token->GetString(), ppVar, this);
CBotFunction::RestoreCall(m_prog->GetFunctions(), nIdent, token->GetString(), ppVar, this);
}
////////////////////////////////////////////////////////////////////////////////
@ -727,12 +735,11 @@ bool CBotStack::RestoreState(FILE* pf, CBotStack* &pStack)
{
unsigned short w;
pStack = nullptr;
if (pStack != this) pStack = nullptr;
if (!ReadWord(pf, w)) return false;
if ( w == 0 ) return true; // 0 - terminator
if ( this == nullptr ) pStack = AllocateStack();
else pStack = AddStack();
if (pStack == nullptr) pStack = AddStack();
if ( w == 2 ) // 2 - m_next2
{

View File

@ -199,7 +199,6 @@ const CBotToken& CBotToken::operator=(const CBotToken& src)
////////////////////////////////////////////////////////////////////////////////
int CBotToken::GetType()
{
if (this == nullptr) return 0;
if (m_type == TokenTypKeyWord) return m_keywordId;
return m_type;
}
@ -225,14 +224,12 @@ void CBotToken::SetString(const std::string& name)
////////////////////////////////////////////////////////////////////////////////
int CBotToken::GetStart()
{
if (this == nullptr) return -1;
return m_start;
}
////////////////////////////////////////////////////////////////////////////////
int CBotToken::GetEnd()
{
if (this == nullptr) return -1;
return m_end;
}
@ -439,6 +436,13 @@ std::unique_ptr<CBotToken> CBotToken::CompileTokens(const std::string& program)
pp = p;
}
// terminator token
nxt = new CBotToken();
nxt->m_type = TokenTypNone;
nxt->m_end = nxt->m_start = pos;
prv->m_next = nxt;
nxt->m_prev = prv;
return std::unique_ptr<CBotToken>(tokenbase);
}

View File

@ -167,11 +167,16 @@ CBotTypResult& CBotTypResult::operator=(const CBotTypResult& src)
m_type = src.m_type;
m_limite = src.m_limite;
m_class = src.m_class;
m_next = nullptr;
if (src.m_next != nullptr )
{
delete m_next;
m_next = new CBotTypResult(*src.m_next);
}
else
{
delete m_next;
m_next = nullptr;
}
return *this;
}

View File

@ -22,6 +22,7 @@
#include "CBot/CBotStack.h"
#include "CBot/CBotInstr/CBotInstr.h"
#include "CBot/CBotVar/CBotVarArray.h"
#include "CBot/CBotVar/CBotVarPointer.h"
#include "CBot/CBotVar/CBotVarClass.h"
@ -70,6 +71,8 @@ CBotVar::CBotVar(const CBotToken &name) : CBotVar()
CBotVar::~CBotVar( )
{
delete m_token;
delete m_InitExpr;
delete m_LimExpr;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -394,12 +394,13 @@ void CBotVarClass::DecrementUse()
CBotVar* pThis = CBotVar::Create("this", CBotTypNullPointer);
pThis->SetPointer(this);
CBotVar* pResult = nullptr;
std::string nom = std::string("~") + m_pClass->GetName();
long ident = 0;
while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, nom, pThis, ppVars, pResult, pile, nullptr)) ; // waits for the end
CBotToken token(nom); // TODO
while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, pThis, ppVars, CBotTypResult(CBotTypVoid), pile, &token)) ; // waits for the end
pile->ResetError(err, start,end);

View File

@ -48,12 +48,12 @@ public:
SetValString(ToString(val));
}
int GetValInt()
int GetValInt() override
{
return FromString<int>(GetValString());
}
float GetValFloat()
float GetValFloat() override
{
return FromString<float>(GetValString());
}

View File

@ -2,8 +2,6 @@ set(SOURCES
CBot.h
CBotCStack.cpp
CBotCStack.h
CBotCallMethode.cpp
CBotCallMethode.h
CBotClass.cpp
CBotClass.h
CBotDebug.cpp

View File

@ -38,7 +38,7 @@ int g_nextFileId = 1;
bool FileClassOpenFile(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
std::string mode;
CBotFileAccessHandler::OpenMode openMode = CBotFileAccessHandler::OpenMode::Read;
// must be a character string
if ( pVar->GetType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
@ -50,8 +50,11 @@ bool FileClassOpenFile(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exc
if ( pVar != nullptr )
{
// recover mode
mode = pVar->GetValString();
if ( mode != "r" && mode != "w" && mode != "a" ) { Exception = CBotErrBadParam; return false; }
std::string mode = pVar->GetValString();
if ( mode == "r" ) openMode = CBotFileAccessHandler::OpenMode::Read;
else if ( mode == "w" ) openMode = CBotFileAccessHandler::OpenMode::Write;
else if ( mode == "a" ) openMode = CBotFileAccessHandler::OpenMode::Append;
else { Exception = CBotErrBadParam; return false; }
// no third parameter
if ( pVar->GetNext() != nullptr ) { Exception = CBotErrOverParam; return false; }
@ -66,16 +69,9 @@ bool FileClassOpenFile(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exc
// which must not be initialized
if ( pVar->IsDefined()) { Exception = CBotErrFileOpen; return false; }
if ( !mode.empty() )
{
// opens the requested file
assert(g_fileHandler != nullptr);
CBotFileAccessHandler::OpenMode openMode;
if ( mode == "r" ) openMode = CBotFileAccessHandler::OpenMode::Read;
else if ( mode == "w" ) openMode = CBotFileAccessHandler::OpenMode::Write;
else if ( mode == "a" ) openMode = CBotFileAccessHandler::OpenMode::Append;
std::unique_ptr<CBotFile> file = g_fileHandler->OpenFile(filename, openMode);
if (!file->Opened()) { Exception = CBotErrFileOpen; return false; }
@ -86,7 +82,7 @@ bool FileClassOpenFile(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exc
// save the file handle
pVar = pThis->GetItem("handle");
pVar->SetValInt(fileHandle);
}
return true;
}

View File

@ -225,8 +225,14 @@ bool rStrFind( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
// puts the result on the stack
std::size_t res = s.find(s2);
pResult->SetValInt( res != std::string::npos ? res : -1 );
if ( res < 0 ) pResult->SetInit( CBotVar::InitType::IS_NAN );
if (res != std::string::npos)
{
pResult->SetValInt(res);
}
else
{
pResult->SetInit(CBotVar::InitType::IS_NAN);
}
return true;
}

View File

@ -165,6 +165,8 @@ set(BASE_SOURCES
graphics/core/nulldevice.cpp
graphics/core/nulldevice.h
graphics/core/texture.h
graphics/core/type.cpp
graphics/core/type.h
graphics/core/vertex.h
graphics/engine/camera.cpp
graphics/engine/camera.h
@ -239,10 +241,14 @@ set(BASE_SOURCES
level/robotmain.h
level/scene_conditions.cpp
level/scene_conditions.h
level/scoreboard.cpp
level/scoreboard.h
math/all.h
math/const.h
math/func.h
math/geometry.h
math/half.cpp
math/half.h
math/intpoint.h
math/matrix.h
math/point.h

View File

@ -674,7 +674,8 @@ bool CApplication::Create()
// Create the robot application.
m_controller = MakeUnique<CController>();
CThread musicLoadThread([this]() {
CThread musicLoadThread([this]()
{
GetLogger()->Debug("Cache sounds...\n");
SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadStart);
@ -685,7 +686,8 @@ bool CApplication::Create()
m_systemUtils->GetCurrentTimeStamp(musicLoadEnd);
float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC);
GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime);
}, "Sound loading thread");
},
"Sound loading thread");
musicLoadThread.Start();
if (m_runSceneCategory == LevelCategory::Max)
@ -1852,9 +1854,10 @@ bool CApplication::GetSceneTestMode()
return m_sceneTest;
}
void CApplication::SetTextInput(bool textInputEnabled)
void CApplication::SetTextInput(bool textInputEnabled, int id)
{
if (textInputEnabled)
m_textInputEnabled[id] = textInputEnabled;
if (std::any_of(m_textInputEnabled.begin(), m_textInputEnabled.end(), [](std::pair<int, bool> v) { return v.second; }))
{
SDL_StartTextInput();
}

View File

@ -35,6 +35,7 @@
#include <string>
#include <vector>
#include <map>
class CEventQueue;
@ -245,7 +246,7 @@ public:
//! Enable/disable text input, this toggles the on-screen keyboard on some platforms
/** This also allows for writing in CJK languages (not tested!), see https://wiki.libsdl.org/Tutorials/TextInput for detailed explanation */
void SetTextInput(bool textInputEnabled);
void SetTextInput(bool textInputEnabled, int id);
//! Moves (warps) the mouse cursor to the specified position (in interface coords)
void MoveMouse(Math::Point pos);
@ -403,4 +404,6 @@ protected:
//! Static buffer for putenv locale
static char m_languageLocale[50];
std::map<int, bool> m_textInputEnabled;
};

View File

@ -46,7 +46,7 @@ void CSignalHandlers::Init(CSystemUtils* systemUtils)
void CSignalHandlers::SignalHandler(int sig)
{
std::string signalStr = StrUtils::ToString(signal);
std::string signalStr = StrUtils::ToString(sig);
switch(sig)
{
case SIGSEGV: signalStr = "SIGSEGV, segmentation fault"; break;

View File

@ -19,6 +19,10 @@
#pragma once
/**
* \file common/error.h
* \brief Definition of the Error enum
*/
/**
* \enum Error
@ -31,6 +35,7 @@ enum Error
ERR_CONTINUE = 2, //!< continues
ERR_STOP = 3, //!< stops
ERR_CMD = 4, //!< unknown command
ERR_OBJ_BUSY = 5, //!< object is busy
ERR_MANIP_FLY = 101, //!< impossible in flight
ERR_MANIP_BUSY = 102, //!< taking: hands already occupied
ERR_MANIP_NIL = 103, //!< taking: nothing has to take
@ -142,6 +147,9 @@ enum Error
INFO_DELETEWORM = 10103, //! < insect killed
INFO_DELETESPIDER = 10104, //! < insect killed
INFO_BEGINSATCOM = 10105, //! < use your SatCom
INFO_TEAM_FINISH = 10110,
INFO_TEAM_DEAD = 10111,
INFO_TEAM_SCORE = 10112,
ERR_MAX //! < number of values
};

View File

@ -172,7 +172,7 @@ enum EventType
EVENT_LABEL16 = 106,
EVENT_LABEL17 = 107,
EVENT_LABEL18 = 108,
EVENT_LABEL19 = 109,
EVENT_LABEL19 = 109, // cursor position overlay
EVENT_LIST0 = 110,
EVENT_LIST1 = 111,
@ -187,6 +187,11 @@ enum EventType
EVENT_LOADING = 120,
EVENT_LABEL_CODE_BATTLE = 121,
EVENT_SCOREBOARD = 130,
EVENT_SCOREBOARD_MAX = 169,
EVENT_TOOLTIP = 200,
EVENT_DIALOG_OK = 300,

View File

@ -39,7 +39,7 @@ public:
/** Construct and Open Stream for writing
*
* \param filename
* \param Mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file
* \param mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file
*
*/
COutputStream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out);
@ -48,7 +48,7 @@ public:
/** Open Stream for writing
*
* \param filename
* \param Mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file
* \param mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file
*
*/
void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out);

View File

@ -38,7 +38,7 @@ public:
/** Open Stream Buffer for writing
*
* \param filename
* \param Mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file
* \param mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file
*
*/
void open(const std::string &filename, std::ios_base::openmode mode);

View File

@ -143,8 +143,14 @@ void InitializeRestext()
stringsText[RT_LOADING_TERRAIN_TEX] = TR("Textures");
stringsText[RT_LOADING_TERRAIN_GEN] = TR("Generating");
stringsText[RT_SCOREBOARD_RESULTS] = TR("Results");
stringsText[RT_SCOREBOARD_RESULTS_TEXT]= TR("The battle has ended");
stringsText[RT_SCOREBOARD_RESULTS_LINE]= TR("%s: %d pts");
stringsEvent[EVENT_LABEL_CODE_BATTLE] = TR("Code battle");
stringsEvent[EVENT_BUTTON_OK] = TR("OK");
stringsEvent[EVENT_BUTTON_CANCEL] = TR("Cancel");
stringsEvent[EVENT_BUTTON_NEXT] = TR("Next");
@ -563,6 +569,7 @@ void InitializeRestext()
stringsErr[ERR_UNKNOWN] = TR("Internal error - tell the developers");
stringsErr[ERR_CMD] = TR("Unknown command");
stringsErr[ERR_OBJ_BUSY] = TR("This object is currently busy");
stringsErr[ERR_MANIP_FLY] = TR("Impossible when flying");
stringsErr[ERR_MANIP_BUSY] = TR("Already carrying something");
stringsErr[ERR_MANIP_NIL] = TR("Nothing to grab");
@ -670,6 +677,9 @@ void InitializeRestext()
stringsErr[INFO_DELETEWORM] = TR("Worm fatally wounded");
stringsErr[INFO_DELETESPIDER] = TR("Spider fatally wounded");
stringsErr[INFO_BEGINSATCOM] = TR("Press \\key help; to read instructions on your SatCom");
stringsErr[INFO_TEAM_FINISH] = TR("<<< Team %s finished! >>>");
stringsErr[INFO_TEAM_DEAD] = TR("<<< Team %s lost! >>>");
stringsErr[INFO_TEAM_SCORE] = TR("<<< Team %s recieved %d points >>>");
@ -718,6 +728,10 @@ void InitializeRestext()
stringsCbot[CBot::CBotErrNoPublic] = TR("Public required");
stringsCbot[CBot::CBotErrNoExpression] = TR("Expression expected after =");
stringsCbot[CBot::CBotErrAmbiguousCall] = TR("Ambiguous call to overloaded function");
stringsCbot[CBot::CBotErrFuncNotVoid] = TR("Function needs return type \"void\"");
stringsCbot[CBot::CBotErrNoClassName] = TR("Class name expected");
stringsCbot[CBot::CBotErrNoReturn] = TR("Non-void function needs \"return;\"");
stringsCbot[CBot::CBotErrDefaultValue] = TR("This parameter needs a default value");
stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero");
stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized");

View File

@ -140,6 +140,10 @@ enum ResTextType
RT_LOADING_TERRAIN_TEX = 222,
RT_LOADING_TERRAIN_GEN = 223,
RT_SCOREBOARD_RESULTS = 230,
RT_SCOREBOARD_RESULTS_TEXT= 231,
RT_SCOREBOARD_RESULTS_LINE= 232,
RT_MAX //! < number of values
};

View File

@ -22,6 +22,8 @@
#include "common/config.h"
#include "common/make_unique.h"
#if defined(PLATFORM_WINDOWS)
#include "common/system/system_windows.h"
#elif defined(PLATFORM_LINUX)
@ -32,8 +34,6 @@
#include "common/system/system_other.h"
#endif
#include "common/make_unique.h"
#include <cassert>
#include <iostream>
#include <algorithm>

View File

@ -26,6 +26,7 @@
#include "graphics/core/color.h"
#include "graphics/core/texture.h"
#include "graphics/core/vertex.h"
#include "math/intpoint.h"
@ -267,8 +268,10 @@ enum PrimitiveType
PRIMITIVE_POINTS,
PRIMITIVE_LINES,
PRIMITIVE_LINE_STRIP,
PRIMITIVE_LINE_LOOP,
PRIMITIVE_TRIANGLES,
PRIMITIVE_TRIANGLE_STRIP
PRIMITIVE_TRIANGLE_STRIP,
PRIMITIVE_TRIANGLE_FAN
};
/**
@ -413,6 +416,14 @@ public:
//! Sets only the texture wrap modes (for faster than thru stage params)
virtual void SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wrapT) = 0;
//! Renders primitive composed of generic vertices
virtual void DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount) = 0;
//! Renders multiple primitives composed of generic vertices
virtual void DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount) = 0;
//! Renders primitive composed of vertices with single texture
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) = 0;

View File

@ -168,6 +168,16 @@ void CNullDevice::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i
{
}
void CNullDevice::DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount)
{
}
void CNullDevice::DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount)
{
}
void CNullDevice::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
int first[], int count[], int drawCount, Color color)
{

View File

@ -81,6 +81,11 @@ public:
void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override;
void DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount) override;
void DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount) override;
void DrawPrimitive(PrimitiveType type, const Vertex* vertices, int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override;
void DrawPrimitive(PrimitiveType type, const VertexTex2* vertices, int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override;
void DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) override;

View File

@ -205,47 +205,6 @@ struct TextureStageParams
}
};
/**
* \struct TexGenMode
* \brief Texture generation mode
*/
enum TexGenMode
{
//! No texture generation
TEX_GEN_NONE,
//! Object linear mode
TEX_GEN_OBJECT_LINEAR,
//! Eye linear mode
TEX_GEN_EYE_LINEAR,
//! Spherical mapping mode
TEX_GEN_SPHERE_MAP,
//! Normal mapping mode
TEX_GEN_NORMAL_MAP,
//! Reflection mapping mode
TEX_GEN_REFLECTION_MAP
};
/**
* \struct TextureGenerationParams
* \brief Parameters for texture coordinate generation
*
* These params define the generation of texture coordinate for given texture unit.
*/
struct TextureGenerationParams
{
struct Coord
{
TexGenMode mode = TEX_GEN_NONE;
float plane[4] = {};
};
Coord coords[4];
void LoadDefault()
{
*this = TextureGenerationParams();
}
};
/**
* \struct Texture
* \brief Info about a texture

View File

@ -0,0 +1,56 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/core/type.cpp
* \brief Type support and conversion
*/
#include "graphics/core/type.h"
#include <cassert>
// Graphics module namespace
namespace Gfx
{
//! Returns size in bytes of given type
int GetTypeSize(Type type)
{
switch (type)
{
case Type::BYTE:
case Type::UBYTE:
return 1;
case Type::SHORT:
case Type::USHORT:
case Type::HALF:
return 2;
case Type::INT:
case Type::UINT:
case Type::FLOAT:
return 4;
case Type::DOUBLE:
return 8;
default:
return 0;
}
}
} // namespace Gfx

62
src/graphics/core/type.h Normal file
View File

@ -0,0 +1,62 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/core/type.h
* \brief Type support and conversion
*/
#pragma once
// Graphics module namespace
namespace Gfx
{
/**
* \enum class Type
* \brief Value types for vertex attributes
*/
enum class Type : unsigned char
{
//! Unsigned byte (8-bit)
UBYTE = 0,
//! Signed byte (8-bit)
BYTE,
//! Unsigned short (16-bit)
USHORT,
//! Signed short (16-bit)
SHORT,
//! Unsigned int (32-bit)
UINT,
//! Signed int (32-bit)
INT,
//! Half precision floating-point (16-bit)
HALF,
//! Single precision floating-point (32-bit)
FLOAT,
//! Double precision floating-point (64-bit)
DOUBLE,
};
//! Returns size in bytes of given type
int GetTypeSize(Type type);
// TODO: functions for conversion between types
} // namespace Gfx

View File

@ -26,11 +26,13 @@
#include "graphics/core/color.h"
#include "graphics/core/type.h"
#include "math/point.h"
#include "math/vector.h"
#include <sstream>
#include <cstdint>
// Graphics module namespace
@ -38,6 +40,58 @@ namespace Gfx
{
/**
* \struct VertexAttribute
* \brief Vertex attribute
*
* This structure contains parameters for a vertex attribute.
*/
struct VertexAttribute
{
//! true enables vertex attribute
bool enabled = false;
//! true means normalized value (integer types only)
bool normalized = false;
//! Number of elements in the vertex attribute.
//! Valid values are 1, 2, 3, and 4. Depends on specific attribute.
unsigned char size = 0;
//! Type of values in vertex attribute
Type type = Type::UBYTE;
//! Offset to the vertex attribute
int offset = 0;
//! Stride of vertex attribute
int stride = 0;
//! Default values used when attribute is disabled
float values[4] = {0.0f, 0.0f, 0.0f, 0.0f};
};
/**
* \struct VertexFormat
* \brief Vertex format
*
* This structure defines vertex formats for generic vertex arrays.
*
* It contains:
* - vertex coordinate specification
* - color specification
* - normal specification
* - texture coordinate 1 specification
* - texture coordinate 2 specification
*/
struct VertexFormat
{
//! Vertex coordinate
VertexAttribute vertex{};
//! Color
VertexAttribute color{};
//! Normal
VertexAttribute normal{};
//! Texture coordinate 1
VertexAttribute tex1{};
//! Texture coordinate 2
VertexAttribute tex2{};
};
/**
* \struct Vertex
* \brief Vertex of a primitive

View File

@ -234,8 +234,6 @@ void CCloud::Create(const std::string& fileName,
m_lines.clear();
for (int y = 0; y < m_brickCount; y++)
CreateLine(0, y, m_brickCount);
return;
}
void CCloud::Flush()

View File

@ -2194,7 +2194,7 @@ void CEngine::SetState(int state, const Color& color)
m_device->SetTextureStageWrap(0, TEX_WRAP_REPEAT, TEX_WRAP_REPEAT);
m_device->SetTextureStageWrap(1, TEX_WRAP_REPEAT, TEX_WRAP_REPEAT);
}
else // if (state & ENG_RSTATE_CLAMP) or otherwise
else if (state & ENG_RSTATE_CLAMP)
{
m_device->SetTextureStageWrap(0, TEX_WRAP_CLAMP, TEX_WRAP_CLAMP);
m_device->SetTextureStageWrap(1, TEX_WRAP_CLAMP, TEX_WRAP_CLAMP);
@ -3087,6 +3087,11 @@ const Math::Matrix& CEngine::GetMatView()
return m_matView;
}
const Math::Matrix& CEngine::GetMatProj()
{
return m_matProj;
}
Math::Vector CEngine::GetEyePt()
{
return m_eyePt;
@ -3261,7 +3266,9 @@ void CEngine::Draw3DScene()
m_device->SetTransform(TRANSFORM_PROJECTION, m_matProj);
m_device->SetTransform(TRANSFORM_VIEW, m_matView);
m_water->DrawBack(); // draws water background
// TODO: This causes a rendering artifact and I can't see anything that breaks if you just comment it out
// So I'll just leave it like that for now ~krzys_h
//m_water->DrawBack(); // draws water background
CProfiler::StartPerformanceCounter(PCNT_RENDER_TERRAIN);
@ -4262,15 +4269,15 @@ void CEngine::UpdateGroundSpotTextures()
else
intensity = Math::Point(ppx-cx, ppy-cy).Length()/dot;
Gfx::Color color;
color.r = Math::Norm(m_groundSpots[i].color.r+intensity);
color.g = Math::Norm(m_groundSpots[i].color.g+intensity);
color.b = Math::Norm(m_groundSpots[i].color.b+intensity);
ppx -= min.x; // on the texture
ppy -= min.y;
Math::IntPoint pp(ppx, ppy);
shadowImg.SetPixel(Math::IntPoint(ppx, ppy), color);
Gfx::Color color = shadowImg.GetPixel(pp);
color.r *= Math::Norm(m_groundSpots[i].color.r+intensity);
color.g *= Math::Norm(m_groundSpots[i].color.g+intensity);
color.b *= Math::Norm(m_groundSpots[i].color.b+intensity);
shadowImg.SetPixel(pp, color);
}
}
}
@ -4298,12 +4305,13 @@ void CEngine::UpdateGroundSpotTextures()
if (intensity < 0.0f) intensity = 0.0f;
Gfx::Color color;
color.r = Math::Norm(m_groundSpots[i].color.r+intensity);
color.g = Math::Norm(m_groundSpots[i].color.g+intensity);
color.b = Math::Norm(m_groundSpots[i].color.b+intensity);
Math::IntPoint pp(ix, iy);
shadowImg.SetPixel(Math::IntPoint(ix, iy), color);
Gfx::Color color = shadowImg.GetPixel(pp);
color.r *= Math::Norm(m_groundSpots[i].color.r+intensity);
color.g *= Math::Norm(m_groundSpots[i].color.g+intensity);
color.b *= Math::Norm(m_groundSpots[i].color.b+intensity);
shadowImg.SetPixel(pp, color);
}
}
}
@ -4351,19 +4359,21 @@ void CEngine::UpdateGroundSpotTextures()
int j = (ix+dot) + (iy+dot) * m_groundMark.dx;
if (m_groundMark.table[j] == 1) // green ?
{
Gfx::Color color;
color.r = Math::Norm(1.0f-intensity);
color.g = 1.0f;
color.b = Math::Norm(1.0f-intensity);
shadowImg.SetPixel(Math::IntPoint(ppx, ppy), color);
Math::IntPoint pp(ppx, ppy);
Gfx::Color color = shadowImg.GetPixel(pp);
color.r *= Math::Norm(1.0f-intensity);
color.g *= 1.0f;
color.b *= Math::Norm(1.0f-intensity);
shadowImg.SetPixel(pp, color);
}
if (m_groundMark.table[j] == 2) // red ?
{
Gfx::Color color;
color.r = 1.0f;
color.g = Math::Norm(1.0f-intensity);
color.b = Math::Norm(1.0f-intensity);
shadowImg.SetPixel(Math::IntPoint(ppx, ppy), color);
Math::IntPoint pp(ppx, ppy);
Gfx::Color color = shadowImg.GetPixel(pp);
color.r *= 1.0f;
color.g *= Math::Norm(1.0f-intensity);
color.b *= Math::Norm(1.0f-intensity);
shadowImg.SetPixel(pp, color);
}
}
}
@ -4401,6 +4411,9 @@ void CEngine::UpdateGroundSpotTextures()
{
int px = x / 4.0f / 254.0f * size.x;
int py = y / 4.0f / 254.0f * size.y;
// This can happen because the shadow??.png textures have a 1 pixel margin around them
if (px < 0 || px >= size.x || py < 0 || py >= size.y)
continue;
shadowImg.SetPixelInt(Math::IntPoint(x-min.x, y-min.y), m_displayGotoImage->GetPixelInt(Math::IntPoint(px, py)));
}
}

View File

@ -1135,6 +1135,8 @@ public:
//! Returns the view matrix
const Math::Matrix& GetMatView();
//! Returns the projection matrix
const Math::Matrix& GetMatProj();
//! Returns the camera center point
TEST_VIRTUAL Math::Vector GetEyePt();
//! Returns the camera target point

View File

@ -131,7 +131,7 @@ bool CLightning::EventFrame(const Event &event)
else
{
assert(obj->Implements(ObjectInterfaceType::Destroyable));
dynamic_cast<CDestroyableObject*>(obj)->DamageObject(DamageType::Lightning);
dynamic_cast<CDestroyableObject*>(obj)->DamageObject(DamageType::Lightning, std::numeric_limits<float>::infinity());
}
}

View File

@ -952,10 +952,9 @@ void CParticle::FrameParticle(float rTime)
{
CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather);
m_particle[i].goal = m_particle[i].pos;
if (object != nullptr)
if (object != nullptr && object->Implements(ObjectInterfaceType::Damageable))
{
assert(object->Implements(ObjectInterfaceType::Damageable));
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Phazer, 0.002f);
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Phazer, 0.002f, m_particle[i].objFather);
}
m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration);
@ -1107,7 +1106,7 @@ void CParticle::FrameParticle(float rTime)
continue;
}
if (m_particle[i].testTime >= 0.1f)
if (m_particle[i].testTime >= 0.05f)
{
m_particle[i].testTime = 0.0f;
@ -1156,8 +1155,10 @@ void CParticle::FrameParticle(float rTime)
m_particle[i].goal = m_particle[i].pos;
if (object != nullptr)
{
assert(object->Implements(ObjectInterfaceType::Damageable));
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Fire, 0.002f);
if (object->Implements(ObjectInterfaceType::Damageable))
{
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Fire, 0.001f, m_particle[i].objFather);
}
m_exploGunCounter++;
@ -1215,7 +1216,7 @@ void CParticle::FrameParticle(float rTime)
continue;
}
if (m_particle[i].testTime >= 0.2f)
if (m_particle[i].testTime >= 0.1f)
{
m_particle[i].testTime = 0.0f;
CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather);
@ -1238,8 +1239,10 @@ void CParticle::FrameParticle(float rTime)
if (object->GetType() != OBJECT_HUMAN)
Play(SOUND_TOUCH, m_particle[i].pos, 1.0f);
assert(object->Implements(ObjectInterfaceType::Damageable));
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Organic, 0.2f); // starts explosion
if (object->Implements(ObjectInterfaceType::Damageable))
{
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Organic, 0.1f, m_particle[i].objFather); // starts explosion
}
}
}
}
@ -1261,7 +1264,7 @@ void CParticle::FrameParticle(float rTime)
continue;
}
if (m_particle[i].testTime >= 0.2f)
if (m_particle[i].testTime >= 0.1f)
{
m_particle[i].testTime = 0.0f;
CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather);
@ -1281,8 +1284,10 @@ void CParticle::FrameParticle(float rTime)
}
else
{
assert(object->Implements(ObjectInterfaceType::Damageable));
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Fire); // starts explosion
if (object->Implements(ObjectInterfaceType::Damageable))
{
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Fire, std::numeric_limits<float>::infinity(), m_particle[i].objFather); // starts explosion
}
}
}
}
@ -1301,7 +1306,7 @@ void CParticle::FrameParticle(float rTime)
continue;
}
if (m_particle[i].testTime >= 0.1f)
if (m_particle[i].testTime >= 0.05f)
{
m_particle[i].testTime = 0.0f;
@ -1338,8 +1343,10 @@ void CParticle::FrameParticle(float rTime)
m_particle[i].goal = m_particle[i].pos;
if (object != nullptr)
{
assert(object->Implements(ObjectInterfaceType::Damageable));
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Organic, 0.002f);
if (object->Implements(ObjectInterfaceType::Damageable))
{
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Organic, 0.001f, m_particle[i].objFather);
}
m_exploGunCounter ++;
@ -2416,7 +2423,7 @@ void CParticle::FrameParticle(float rTime)
if (object != nullptr)
{
assert(object->Implements(ObjectInterfaceType::Damageable));
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Tower);
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Tower, std::numeric_limits<float>::infinity(), m_particle[i].objFather);
}
}
@ -3502,6 +3509,7 @@ CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos,
box2.z += min;
CObject* best = nullptr;
float best_dist = std::numeric_limits<float>::infinity();
bool shield = false;
for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
{
@ -3535,7 +3543,7 @@ CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos,
{
continue;
}
if (!obj->Implements(ObjectInterfaceType::Damageable)) continue;
if (!obj->Implements(ObjectInterfaceType::Damageable) && !obj->IsBulletWall()) continue;
Math::Vector oPos = obj->GetPosition();
@ -3563,8 +3571,12 @@ CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos,
// Test the center of the object, which is necessary for objects
// that have no sphere in the center (station).
float dist = Math::Distance(oPos, pos)-4.0f;
if (dist < min)
float obj_dist = Math::Distance(old, oPos);
if (dist < min && obj_dist < best_dist)
{
best = obj;
best_dist = obj_dist;
}
for (const auto& crashSphere : obj->GetAllCrashSpheres())
{
@ -3577,8 +3589,12 @@ CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos,
Math::Vector p = Math::Projection(old, pos, oPos);
float ddist = Math::Distance(p, oPos)-oRadius;
if (ddist < min)
float obj_dist = Math::Distance(old, oPos);
if (ddist < min && obj_dist < best_dist)
{
best = obj;
best_dist = obj_dist;
}
}
}
@ -3724,4 +3740,24 @@ Color CParticle::GetFogColor(Math::Vector pos)
return result;
}
void CParticle::CutObjectLink(CObject* obj)
{
for (int i = 0; i < MAXPARTICULE*MAXPARTITYPE; i++)
{
if (!m_particle[i].used) continue;
if (m_particle[i].objLink == obj)
{
// If the object this particle's coordinates are linked to doesn't exist anymore, remove the particle
DeleteRank(i);
}
if (m_particle[i].objFather == obj)
{
// If the object that spawned this partcle doesn't exist anymore, remove the link
m_particle[i].objFather = nullptr;
}
}
}
} // namespace Gfx

View File

@ -291,6 +291,9 @@ public:
//! Draws all the particles
void DrawParticle(int sheet);
//! Indicates that the object binds to the particle no longer exists, without deleting it
void CutObjectLink(CObject* obj);
protected:
//! Removes a particle of given rank
void DeleteRank(int rank);

View File

@ -2157,6 +2157,9 @@ bool CPyro::BurnIsKeepPart(int part)
void CPyro::BurnTerminate()
{
if (m_object == nullptr)
return;
if (m_type == PT_BURNO) // organic object is burning?
{
DeleteObject(true, true); // removes the insect
@ -2296,6 +2299,7 @@ void CPyro::FallProgress(float rTime)
if (floor) // reaches the ground?
{
assert(m_object->Implements(ObjectInterfaceType::Destroyable));
// TODO: implement "killer"?
dynamic_cast<CDestroyableObject*>(m_object)->DestroyObject(DestructionType::Explosion);
}
}
@ -2319,6 +2323,7 @@ void CPyro::FallProgress(float rTime)
else
{
assert(m_object->Implements(ObjectInterfaceType::Destroyable));
// TODO: implement "killer"?
dynamic_cast<CDestroyableObject*>(m_object)->DestroyObject(DestructionType::Explosion);
}
}

View File

@ -229,7 +229,7 @@ bool CTerrain::LoadResources(const std::string& fileName)
if ( (data->surface->w != size) || (data->surface->h != size) )
{
GetLogger()->Error("Invalid resource file\n");
GetLogger()->Error("Invalid resource file! Expected %dx%d\n", size, size);
return false;
}
@ -311,10 +311,11 @@ bool CTerrain::LoadRelief(const std::string &fileName, float scaleRelief,
ImageData *data = img.GetData();
int size = (m_mosaicCount*m_brickCount)+1;
GetLogger()->Debug("Expected relief size for current terrain configuration is %dx%d\n", size, size);
if ( (data->surface->w != size) || (data->surface->h != size) )
{
GetLogger()->Error("Invalid relief file!\n");
GetLogger()->Error("Invalid relief file! Expected %dx%d\n", size, size);
return false;
}

View File

@ -643,37 +643,37 @@ UTF8Char CText::TranslateSpecialChar(int specialChar)
case CHAR_NEWLINE:
// Unicode: U+21B2
ch.c1 = 0xE2;
ch.c2 = 0x86;
ch.c3 = 0xB2;
ch.c1 = static_cast<char>(0xE2);
ch.c2 = static_cast<char>(0x86);
ch.c3 = static_cast<char>(0xB2);
break;
case CHAR_DOT:
// Unicode: U+23C5
ch.c1 = 0xE2;
ch.c2 = 0x8F;
ch.c3 = 0x85;
ch.c1 = static_cast<char>(0xE2);
ch.c2 = static_cast<char>(0x8F);
ch.c3 = static_cast<char>(0x85);
break;
case CHAR_SQUARE:
// Unicode: U+25FD
ch.c1 = 0xE2;
ch.c2 = 0x97;
ch.c3 = 0xBD;
ch.c1 = static_cast<char>(0xE2);
ch.c2 = static_cast<char>(0x97);
ch.c3 = static_cast<char>(0xBD);
break;
case CHAR_SKIP_RIGHT:
// Unicode: U+25B6
ch.c1 = 0xE2;
ch.c2 = 0x96;
ch.c3 = 0xB6;
ch.c1 = static_cast<char>(0xE2);
ch.c2 = static_cast<char>(0x96);
ch.c3 = static_cast<char>(0xB6);
break;
case CHAR_SKIP_LEFT:
// Unicode: U+25C0
ch.c1 = 0xE2;
ch.c2 = 0x97;
ch.c3 = 0x80;
ch.c1 = static_cast<char>(0xE2);
ch.c2 = static_cast<char>(0x97);
ch.c3 = static_cast<char>(0x80);
break;
default:

View File

@ -258,11 +258,25 @@ bool CGL14Device::Create()
{
GetLogger()->Info("Core VBO supported\n", glMajor, glMinor);
m_vertexBufferType = VBT_VBO_CORE;
// Set function pointers
m_glGenBuffers = glGenBuffers;
m_glDeleteBuffers = glDeleteBuffers;
m_glBindBuffer = glBindBuffer;
m_glBufferData = glBufferData;
m_glBufferSubData = glBufferSubData;
}
else if (vboARB) // VBO ARB extension available
{
GetLogger()->Info("ARB VBO supported\n");
m_vertexBufferType = VBT_VBO_ARB;
// Set function pointers
m_glGenBuffers = glGenBuffersARB;
m_glDeleteBuffers = glDeleteBuffersARB;
m_glBindBuffer = glBindBufferARB;
m_glBufferData = glBufferDataARB;
m_glBufferSubData = glBufferSubDataARB;
}
else // no VBO support
{
@ -800,8 +814,6 @@ Texture CGL14Device::CreateDepthTexture(int width, int height, int depth)
GLuint format = GL_DEPTH_COMPONENT;
if (m_shadowMappingSupport == SMS_CORE)
{
switch (depth)
{
case 16:
@ -818,26 +830,6 @@ Texture CGL14Device::CreateDepthTexture(int width, int height, int depth)
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
}
else
{
switch (depth)
{
case 16:
format = GL_DEPTH_COMPONENT16_ARB;
break;
case 24:
format = GL_DEPTH_COMPONENT24_ARB;
break;
case 32:
format = GL_DEPTH_COMPONENT32_ARB;
break;
}
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
}
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
@ -1379,6 +1371,168 @@ void CGL14Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i
glDisableClientState(GL_COLOR_ARRAY);
}
void CGL14Device::DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount)
{
const char *ptr = reinterpret_cast<const char*>(vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(format.vertex.size,
TransformType(format.vertex.type),
format.vertex.stride,
ptr + format.vertex.offset);
if (format.color.enabled)
{
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(format.color.size,
TransformType(format.color.type),
format.color.stride,
ptr + format.color.offset);
}
else
glColor4fv(format.color.values);
if (format.normal.enabled)
{
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(TransformType(format.normal.type),
format.normal.stride,
ptr + format.normal.offset);
}
else
glNormal3fv(format.normal.values);
glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
if (format.tex1.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex1.size,
TransformType(format.tex1.type),
format.tex1.stride,
ptr + format.tex1.offset);
}
else
glTexCoord2fv(format.tex1.values);
glClientActiveTexture(GL_TEXTURE0 + m_remap[1]);
if (format.tex2.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex2.size,
TransformType(format.tex2.type),
format.tex2.stride,
ptr + format.tex2.offset);
}
else
glTexCoord2fv(format.tex2.values);
glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
glDisableClientState(GL_VERTEX_ARRAY);
if (format.color.enabled) glDisableClientState(GL_COLOR_ARRAY);
if (format.normal.enabled) glDisableClientState(GL_NORMAL_ARRAY);
if (format.tex1.enabled)
{
glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
if (format.tex2.enabled)
{
glClientActiveTexture(GL_TEXTURE0 + m_remap[1]);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}
void CGL14Device::DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount)
{
const char *ptr = reinterpret_cast<const char*>(vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(format.vertex.size,
TransformType(format.vertex.type),
format.vertex.stride,
ptr + format.vertex.offset);
if (format.color.enabled)
{
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(format.color.size,
TransformType(format.color.type),
format.color.stride,
ptr + format.color.offset);
}
else
glColor4fv(format.color.values);
if (format.normal.enabled)
{
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(TransformType(format.normal.type),
format.normal.stride,
ptr + format.normal.offset);
}
else
glNormal3fv(format.normal.values);
glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
if (format.tex1.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex1.size,
TransformType(format.tex1.type),
format.tex1.stride,
ptr + format.tex1.offset);
}
else
glTexCoord2fv(format.tex1.values);
glClientActiveTexture(GL_TEXTURE0 + m_remap[1]);
if (format.tex2.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex2.size,
TransformType(format.tex2.type),
format.tex2.stride,
ptr + format.tex2.offset);
}
else
glTexCoord2fv(format.tex2.values);
GLenum t = TranslateGfxPrimitive(type);
if (m_multiDrawArrays)
{
glMultiDrawArrays(t, first, count, drawCount);
}
else
{
for (int i = 0; i < drawCount; i++)
glDrawArrays(t, first[i], count[i]);
}
glDisableClientState(GL_VERTEX_ARRAY);
if (format.color.enabled) glDisableClientState(GL_COLOR_ARRAY);
if (format.normal.enabled) glDisableClientState(GL_NORMAL_ARRAY);
if (format.tex1.enabled)
{
glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
if (format.tex2.enabled)
{
glClientActiveTexture(GL_TEXTURE0 + m_remap[1]);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}
void CGL14Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
int first[], int count[], int drawCount, Color color)
{
@ -1494,20 +1648,10 @@ unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const
info.vertexCount = vertexCount;
info.bufferId = 0;
if(m_vertexBufferType == VBT_VBO_CORE)
{
glGenBuffers(1, &info.bufferId);
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
glGenBuffersARB(1, &info.bufferId);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
m_glGenBuffers(1, &info.bufferId);
m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW);
m_glBindBuffer(GL_ARRAY_BUFFER, 0);
m_vboObjects[id] = info;
}
@ -1538,20 +1682,10 @@ unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const
info.vertexCount = vertexCount;
info.bufferId = 0;
if(m_vertexBufferType == VBT_VBO_CORE)
{
glGenBuffers(1, &info.bufferId);
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
glGenBuffersARB(1, &info.bufferId);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
m_glGenBuffers(1, &info.bufferId);
m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW);
m_glBindBuffer(GL_ARRAY_BUFFER, 0);
m_vboObjects[id] = info;
}
@ -1582,20 +1716,10 @@ unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const
info.vertexCount = vertexCount;
info.bufferId = 0;
if(m_vertexBufferType == VBT_VBO_CORE)
{
glGenBuffers(1, &info.bufferId);
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
glGenBuffersARB(1, &info.bufferId);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
m_glGenBuffers(1, &info.bufferId);
m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW);
m_glBindBuffer(GL_ARRAY_BUFFER, 0);
m_vboObjects[id] = info;
}
@ -1626,18 +1750,9 @@ void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
info.vertexType = VERTEX_TYPE_NORMAL;
info.vertexCount = vertexCount;
if(m_vertexBufferType == VBT_VBO_CORE)
{
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW);
m_glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
@ -1662,18 +1777,9 @@ void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
info.vertexType = VERTEX_TYPE_TEX2;
info.vertexCount = vertexCount;
if(m_vertexBufferType == VBT_VBO_CORE)
{
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW);
m_glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
@ -1698,18 +1804,9 @@ void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
info.vertexType = VERTEX_TYPE_COL;
info.vertexCount = vertexCount;
if(m_vertexBufferType == VBT_VBO_CORE)
{
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW);
m_glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
@ -1729,10 +1826,7 @@ void CGL14Device::DrawStaticBuffer(unsigned int bufferId)
if (it == m_vboObjects.end())
return;
if(m_vertexBufferType == VBT_VBO_CORE)
glBindBuffer(GL_ARRAY_BUFFER, (*it).second.bufferId);
else
glBindBufferARB(GL_ARRAY_BUFFER_ARB, (*it).second.bufferId);
m_glBindBuffer(GL_ARRAY_BUFFER, (*it).second.bufferId);
if ((*it).second.vertexType == VERTEX_TYPE_NORMAL)
{
@ -1795,10 +1889,7 @@ void CGL14Device::DrawStaticBuffer(unsigned int bufferId)
glDisableClientState(GL_COLOR_ARRAY);
}
if(m_vertexBufferType == VBT_VBO_CORE)
glBindBuffer(GL_ARRAY_BUFFER, 0);
else
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
m_glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
@ -1814,10 +1905,7 @@ void CGL14Device::DestroyStaticBuffer(unsigned int bufferId)
if (it == m_vboObjects.end())
return;
if(m_vertexBufferType == VBT_VBO_CORE)
glDeleteBuffers(1, &(*it).second.bufferId);
else
glDeleteBuffersARB(1, &(*it).second.bufferId);
m_glDeleteBuffers(1, &(*it).second.bufferId);
m_vboObjects.erase(it);
}

View File

@ -119,6 +119,11 @@ public:
void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override;
virtual void DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount) override;
virtual void DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount) override;
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override;
virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount,
@ -290,6 +295,14 @@ private:
bool m_shadowMapping = false;
//! true means that quality shadows are enabled
bool m_shadowQuality = true;
//! Pointers to OpenGL functions
PFNGLGENBUFFERSPROC m_glGenBuffers = nullptr;
PFNGLDELETEBUFFERSPROC m_glDeleteBuffers = nullptr;
PFNGLBINDBUFFERPROC m_glBindBuffer = nullptr;
PFNGLBUFFERDATAPROC m_glBufferData = nullptr;
PFNGLBUFFERSUBDATAPROC m_glBufferSubData = nullptr;
};

View File

@ -242,7 +242,7 @@ bool CGL21Device::Create()
glViewport(0, 0, m_config.size.x, m_config.size.y);
// this is set in shader
int numLights = 8;
int numLights = 4;
m_lights = std::vector<Light>(numLights, Light());
m_lightsEnabled = std::vector<bool> (numLights, false);
@ -408,7 +408,7 @@ bool CGL21Device::Create()
uni.fogColor = glGetUniformLocation(m_normalProgram, "uni_FogColor");
uni.shadowColor = glGetUniformLocation(m_normalProgram, "uni_ShadowColor");
uni.lightingEnabled = glGetUniformLocation(m_normalProgram, "uni_LightingEnabled");
uni.lightCount = glGetUniformLocation(m_normalProgram, "uni_LightCount");
uni.ambientColor = glGetUniformLocation(m_normalProgram, "uni_Material.ambient");
uni.diffuseColor = glGetUniformLocation(m_normalProgram, "uni_Material.diffuse");
@ -417,12 +417,6 @@ bool CGL21Device::Create()
GLchar name[64];
for (int i = 0; i < 8; i++)
{
sprintf(name, "uni_Light[%d].Enabled", i);
uni.lights[i].enabled = glGetUniformLocation(m_normalProgram, name);
sprintf(name, "uni_Light[%d].Type", i);
uni.lights[i].type = glGetUniformLocation(m_normalProgram, name);
sprintf(name, "uni_Light[%d].Position", i);
uni.lights[i].position = glGetUniformLocation(m_normalProgram, name);
@ -434,18 +428,6 @@ bool CGL21Device::Create()
sprintf(name, "uni_Light[%d].Specular", i);
uni.lights[i].specular = glGetUniformLocation(m_normalProgram, name);
sprintf(name, "uni_Light[%d].Attenuation", i);
uni.lights[i].attenuation = glGetUniformLocation(m_normalProgram, name);
sprintf(name, "uni_Light[%d].SpotDirection", i);
uni.lights[i].spotDirection = glGetUniformLocation(m_normalProgram, name);
sprintf(name, "uni_Light[%d].Exponent", i);
uni.lights[i].spotExponent = glGetUniformLocation(m_normalProgram, name);
sprintf(name, "uni_Light[%d].SpotCutoff", i);
uni.lights[i].spotCutoff = glGetUniformLocation(m_normalProgram, name);
}
// Set default uniform values
@ -476,10 +458,7 @@ bool CGL21Device::Create()
glUniform1f(uni.shadowColor, 0.5f);
glUniform1i(uni.lightingEnabled, 0);
for (int i = 0; i < 8; i++)
glUniform1i(uni.lights[i].enabled, 0);
glUniform1i(uni.lightCount, 0);
}
// Obtain uniform locations from interface rendering program and initialize them
@ -594,6 +573,7 @@ void CGL21Device::ConfigChanged(const DeviceConfig& newConfig)
// Reset state
m_lighting = false;
m_updateLights = true;
glViewport(0, 0, m_config.size.x, m_config.size.y);
@ -721,36 +701,7 @@ void CGL21Device::SetLight(int index, const Light &light)
m_lights[index] = light;
LightLocations &loc = m_uniforms[m_mode].lights[index];
glUniform4fv(loc.ambient, 1, light.ambient.Array());
glUniform4fv(loc.diffuse, 1, light.diffuse.Array());
glUniform4fv(loc.specular, 1, light.specular.Array());
glUniform3f(loc.attenuation, light.attenuation0, light.attenuation1, light.attenuation2);
if (light.type == LIGHT_DIRECTIONAL)
{
glUniform1i(loc.type, 1);
glUniform4f(loc.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f);
}
else if (light.type == LIGHT_POINT)
{
glUniform1i(loc.type, 2);
glUniform4f(loc.position, light.position.x, light.position.y, light.position.z, 1.0f);
glUniform3f(loc.spotDirection, 0.0f, 1.0f, 0.0f);
glUniform1f(loc.spotCutoff, -1.0f);
glUniform1f(loc.spotExponent, 1.0f);
}
else if (light.type == LIGHT_SPOT)
{
glUniform1i(loc.type, 3);
glUniform4f(loc.position, light.position.x, light.position.y, light.position.z, 1.0f);
glUniform3f(loc.spotDirection, -light.direction.x, -light.direction.y, -light.direction.z);
glUniform1f(loc.spotCutoff, std::cos(light.spotAngle));
glUniform1f(loc.spotExponent, light.spotIntensity);
}
m_updateLights = true;
}
void CGL21Device::SetLightEnabled(int index, bool enabled)
@ -760,7 +711,7 @@ void CGL21Device::SetLightEnabled(int index, bool enabled)
m_lightsEnabled[index] = enabled;
glUniform1i(m_uniforms[m_mode].lights[index].enabled, enabled ? 1 : 0);
m_updateLights = true;
}
/** If image is invalid, returns invalid texture.
@ -798,12 +749,13 @@ Texture CGL21Device::CreateTexture(ImageData *data, const TextureCreateParams &p
result.originalSize = result.size;
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &result.id);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, result.id);
glEnable(GL_TEXTURE_2D);
// Set texture parameters
GLint minF = GL_NEAREST, magF = GL_NEAREST;
int mipmapLevel = 1;
@ -991,7 +943,7 @@ void CGL21Device::SetTexture(int index, const Texture &texture)
glBindTexture(GL_TEXTURE_2D, texture.id);
// Params need to be updated for the new bound texture
UpdateTextureStatus();
UpdateTextureState(index);
UpdateTextureParams(index);
}
@ -1009,7 +961,7 @@ void CGL21Device::SetTexture(int index, unsigned int textureId)
glBindTexture(GL_TEXTURE_2D, textureId);
// Params need to be updated for the new bound texture
UpdateTextureStatus();
UpdateTextureState(index);
UpdateTextureParams(index);
}
@ -1024,15 +976,54 @@ void CGL21Device::SetTextureEnabled(int index, bool enabled)
if (same)
return; // nothing to do
UpdateTextureStatus();
UpdateTextureState(index);
}
void CGL21Device::UpdateTextureStatus()
void CGL21Device::UpdateTextureState(int index)
{
for (int i = 0; i < 3; i++)
bool enabled = m_texturesEnabled[index] && (m_currentTextures[index].id != 0);
glUniform1i(m_uniforms[m_mode].textureEnabled[index], enabled ? 1 : 0);
}
void CGL21Device::UpdateLights()
{
bool enabled = m_texturesEnabled[i] && (m_currentTextures[i].id != 0);
glUniform1i(m_uniforms[m_mode].textureEnabled[i], enabled ? 1 : 0);
m_updateLights = false;
// If not in normal rendering mode, return immediately
if (m_mode != 0) return;
// Lighting enabled
if (m_lighting)
{
int index = 0;
// Iterate all lights
for (unsigned int i = 0; i < m_lights.size(); i++)
{
// If disabled, ignore and continue
if (!m_lightsEnabled[i]) continue;
// If not directional, ignore and continue
if (m_lights[i].type != LIGHT_DIRECTIONAL) continue;
Light &light = m_lights[i];
LightLocations &uni = m_uniforms[m_mode].lights[index];
glUniform4fv(uni.ambient, 1, light.ambient.Array());
glUniform4fv(uni.diffuse, 1, light.diffuse.Array());
glUniform4fv(uni.specular, 1, light.specular.Array());
glUniform4f(uni.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f);
index++;
}
glUniform1i(m_uniforms[m_mode].lightCount, index);
}
// Lighting disabled
else
{
glUniform1i(m_uniforms[m_mode].lightCount, 0);
}
}
@ -1044,6 +1035,12 @@ inline void CGL21Device::BindVBO(GLuint vbo)
m_currentVBO = vbo;
}
inline void CGL21Device::BindTexture(int index, GLuint texture)
{
glActiveTexture(GL_TEXTURE0 + index);
glBindTexture(GL_TEXTURE_2D, texture);
}
/**
Sets the texture parameters for the given texture stage.
If the given texture was not set (bound) yet, nothing happens.
@ -1121,6 +1118,8 @@ void CGL21Device::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode
void CGL21Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount,
Color color)
{
if (m_updateLights) UpdateLights();
BindVBO(0);
Vertex* vs = const_cast<Vertex*>(vertices);
@ -1148,6 +1147,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int
void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount,
Color color)
{
if (m_updateLights) UpdateLights();
BindVBO(0);
VertexTex2* vs = const_cast<VertexTex2*>(vertices);
@ -1180,6 +1181,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices,
void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount)
{
if (m_updateLights) UpdateLights();
BindVBO(0);
VertexCol* vs = const_cast<VertexCol*>(vertices);
@ -1196,9 +1199,171 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i
glDisableClientState(GL_COLOR_ARRAY);
}
void CGL21Device::DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount)
{
if (m_updateLights) UpdateLights();
BindVBO(0);
const char *ptr = reinterpret_cast<const char*>(vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(format.vertex.size,
TransformType(format.vertex.type),
format.vertex.stride,
ptr + format.vertex.offset);
if (format.color.enabled)
{
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(format.color.size,
TransformType(format.color.type),
format.color.stride,
ptr + format.color.offset);
}
else
glColor4fv(format.color.values);
if (format.normal.enabled)
{
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(TransformType(format.normal.type),
format.normal.stride,
ptr + format.normal.offset);
}
else
glNormal3fv(format.normal.values);
glClientActiveTexture(GL_TEXTURE0);
if (format.tex1.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex1.size,
TransformType(format.tex1.type),
format.tex1.stride,
ptr + format.tex1.offset);
}
else
glTexCoord2fv(format.tex1.values);
glClientActiveTexture(GL_TEXTURE1);
if (format.tex2.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex2.size,
TransformType(format.tex2.type),
format.tex2.stride,
ptr + format.tex2.offset);
}
else
glTexCoord2fv(format.tex2.values);
glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
glDisableClientState(GL_VERTEX_ARRAY);
if (format.color.enabled) glDisableClientState(GL_COLOR_ARRAY);
if (format.normal.enabled) glDisableClientState(GL_NORMAL_ARRAY);
if (format.tex1.enabled)
{
glClientActiveTexture(GL_TEXTURE0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
if (format.tex2.enabled)
{
glClientActiveTexture(GL_TEXTURE1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}
void CGL21Device::DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount)
{
if (m_updateLights) UpdateLights();
BindVBO(0);
const char *ptr = reinterpret_cast<const char*>(vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(format.vertex.size,
TransformType(format.vertex.type),
format.vertex.stride,
ptr + format.vertex.offset);
if (format.color.enabled)
{
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(format.color.size,
TransformType(format.color.type),
format.color.stride,
ptr + format.color.offset);
}
else
glColor4fv(format.color.values);
if (format.normal.enabled)
{
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(TransformType(format.normal.type),
format.normal.stride,
ptr + format.normal.offset);
}
else
glNormal3fv(format.normal.values);
glClientActiveTexture(GL_TEXTURE0);
if (format.tex1.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex1.size,
TransformType(format.tex1.type),
format.tex1.stride,
ptr + format.tex1.offset);
}
else
glTexCoord2fv(format.tex1.values);
glClientActiveTexture(GL_TEXTURE1);
if (format.tex2.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex2.size,
TransformType(format.tex2.type),
format.tex2.stride,
ptr + format.tex2.offset);
}
else
glTexCoord2fv(format.tex2.values);
glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount);
glDisableClientState(GL_VERTEX_ARRAY);
if (format.color.enabled) glDisableClientState(GL_COLOR_ARRAY);
if (format.normal.enabled) glDisableClientState(GL_NORMAL_ARRAY);
if (format.tex1.enabled)
{
glClientActiveTexture(GL_TEXTURE0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
if (format.tex2.enabled)
{
glClientActiveTexture(GL_TEXTURE1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}
void CGL21Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
int first[], int count[], int drawCount, Color color)
{
if (m_updateLights) UpdateLights();
BindVBO(0);
Vertex* vs = const_cast<Vertex*>(vertices);
@ -1225,6 +1390,8 @@ void CGL21Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices,
int first[], int count[], int drawCount, Color color)
{
if (m_updateLights) UpdateLights();
BindVBO(0);
VertexTex2* vs = const_cast<VertexTex2*>(vertices);
@ -1258,6 +1425,8 @@ void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices,
void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices,
int first[], int count[], int drawCount)
{
if (m_updateLights) UpdateLights();
BindVBO(0);
VertexCol* vs = const_cast<VertexCol*>(vertices);
@ -1418,6 +1587,8 @@ void CGL21Device::DrawStaticBuffer(unsigned int bufferId)
if (it == m_vboObjects.end())
return;
if (m_updateLights) UpdateLights();
BindVBO((*it).second.bufferId);
if ((*it).second.vertexType == VERTEX_TYPE_NORMAL)
@ -1585,9 +1756,11 @@ void CGL21Device::SetRenderState(RenderState state, bool enabled)
}
else if (state == RENDER_STATE_LIGHTING)
{
if (m_lighting == enabled) return;
m_lighting = enabled;
glUniform1i(m_uniforms[m_mode].lightingEnabled, enabled ? 1 : 0);
m_updateLights = true;
return;
}

View File

@ -100,6 +100,11 @@ public:
void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override;
virtual void DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount) override;
virtual void DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount) override;
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override;
virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount,
@ -178,10 +183,14 @@ public:
private:
//! Updates the texture params for given texture stage
void UpdateTextureParams(int index);
//! Updates texture status
void UpdateTextureStatus();
//! Updates texture state
void UpdateTextureState(int index);
//! Update light parameters
void UpdateLights();
//! Binds VBO
inline void BindVBO(GLuint vbo);
//! Binds texture
inline void BindTexture(int index, GLuint texture);
private:
//! Current config
@ -203,6 +212,8 @@ private:
//! Whether lighting is enabled
bool m_lighting = false;
//! true means that lights need to be updated
bool m_updateLights = false;
//! Current lights
std::vector<Light> m_lights;
//! Current lights enable status

View File

@ -233,7 +233,7 @@ bool CGL33Device::Create()
glViewport(0, 0, m_config.size.x, m_config.size.y);
// this is set in shader
m_capabilities.maxLights = 8;
m_capabilities.maxLights = 4;
m_lights = std::vector<Light>(m_capabilities.maxLights, Light());
m_lightsEnabled = std::vector<bool>(m_capabilities.maxLights, false);
@ -381,14 +381,14 @@ bool CGL33Device::Create()
uni.shadowColor = glGetUniformLocation(m_normalProgram, "uni_ShadowColor");
uni.lightingEnabled = glGetUniformLocation(m_normalProgram, "uni_LightingEnabled");
uni.lightCount = glGetUniformLocation(m_normalProgram, "uni_LightCount");
uni.ambientColor = glGetUniformLocation(m_normalProgram, "uni_AmbientColor");
uni.diffuseColor = glGetUniformLocation(m_normalProgram, "uni_DiffuseColor");
uni.specularColor = glGetUniformLocation(m_normalProgram, "uni_SpecularColor");
GLchar name[64];
for (int i = 0; i < 8; i++)
for (int i = 0; i < m_capabilities.maxLights; i++)
{
LightLocations &light = uni.lights[i];
@ -440,12 +440,9 @@ bool CGL33Device::Create()
glUniform1f(uni.shadowColor, 0.5f);
glUniform1i(uni.alphaTestEnabled, 0);
glUniform1f(uni.alphaReference, 1.0f);
glUniform1f(uni.alphaReference, 0.5f);
glUniform1i(uni.lightingEnabled, 0);
for (int i = 0; i < 8; i++)
glUniform1i(uni.lights[i].enabled, 0);
glUniform1i(uni.lightCount, 0);
}
// Obtain uniform locations for interface program
@ -523,21 +520,18 @@ bool CGL33Device::Create()
m_framebuffers["default"] = MakeUnique<CDefaultFramebuffer>(framebufferParams);
// create dynamic buffers
for (int i = 0; i < 3; i++)
{
glGenVertexArrays(1, &m_dynamicBuffers[i].vao);
// create dynamic buffer
glGenVertexArrays(1, &m_dynamicBuffer.vao);
m_dynamicBuffers[i].size = 4 * 1024 * 1024;
m_dynamicBuffers[i].offset = 0;
m_dynamicBuffer.size = 4 * 1024 * 1024;
m_dynamicBuffer.offset = 0;
glGenBuffers(1, &m_dynamicBuffers[i].vbo);
glBindBuffer(GL_ARRAY_BUFFER, m_dynamicBuffers[i].vbo);
glBufferData(GL_ARRAY_BUFFER, m_dynamicBuffers[i].size, nullptr, GL_STREAM_DRAW);
glGenBuffers(1, &m_dynamicBuffer.vbo);
glBindBuffer(GL_ARRAY_BUFFER, m_dynamicBuffer.vbo);
glBufferData(GL_ARRAY_BUFFER, m_dynamicBuffer.size, nullptr, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_vboMemory += m_dynamicBuffers[i].size;
}
m_vboMemory += m_dynamicBuffer.size;
GetLogger()->Info("CDevice created successfully\n");
@ -563,13 +557,10 @@ void CGL33Device::Destroy()
DestroyAllTextures();
// delete dynamic buffer
for (int i = 0; i < 3; i++)
{
glDeleteVertexArrays(1, &m_dynamicBuffers[i].vao);
glDeleteBuffers(1, &m_dynamicBuffers[i].vbo);
glDeleteVertexArrays(1, &m_dynamicBuffer.vao);
glDeleteBuffers(1, &m_dynamicBuffer.vbo);
m_vboMemory -= m_dynamicBuffers[i].size;
}
m_vboMemory -= m_dynamicBuffer.size;
m_lights.clear();
m_lightsEnabled.clear();
@ -643,7 +634,9 @@ void CGL33Device::SetRenderMode(RenderMode mode)
m_uni = &m_uniforms[m_mode];
UpdateRenderingMode();
UpdateTextureState(0);
UpdateTextureState(1);
UpdateTextureState(2);
}
void CGL33Device::SetTransform(TransformType type, const Math::Matrix &matrix)
@ -714,23 +707,7 @@ void CGL33Device::SetLight(int index, const Light &light)
m_lights[index] = light;
LightLocations &uni = m_uni->lights[index];
glUniform4fv(uni.ambient, 1, light.ambient.Array());
glUniform4fv(uni.diffuse, 1, light.diffuse.Array());
glUniform4fv(uni.specular, 1, light.specular.Array());
glUniform3f(uni.attenuation, light.attenuation0, light.attenuation1, light.attenuation2);
if (light.type == LIGHT_DIRECTIONAL)
{
glUniform4f(uni.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f);
}
else
{
glUniform4f(uni.position, light.position.x, light.position.y, light.position.z, 1.0f);
}
// TODO: add spotlight params
m_updateLights = true;
}
void CGL33Device::SetLightEnabled(int index, bool enabled)
@ -740,7 +717,7 @@ void CGL33Device::SetLightEnabled(int index, bool enabled)
m_lightsEnabled[index] = enabled;
glUniform1i(m_uni->lights[index].enabled, enabled ? 1 : 0);
m_updateLights = true;
}
/** If image is invalid, returns invalid texture.
@ -775,10 +752,9 @@ Texture CGL33Device::CreateTexture(ImageData *data, const TextureCreateParams &p
result.originalSize = result.size;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &result.id);
glBindTexture(GL_TEXTURE_2D, result.id);
BindTexture(m_freeTexture, result.id);
// Set texture parameters
GLint minF = GL_NEAREST, magF = GL_NEAREST;
@ -841,9 +817,6 @@ Texture CGL33Device::CreateTexture(ImageData *data, const TextureCreateParams &p
m_allTextures.insert(result);
// Restore the previous state of 1st stage
glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
return result;
}
@ -855,10 +828,9 @@ Texture CGL33Device::CreateDepthTexture(int width, int height, int depth)
result.size.x = width;
result.size.y = height;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &result.id);
glBindTexture(GL_TEXTURE_2D, result.id);
BindTexture(m_freeTexture, result.id);
GLuint format = GL_DEPTH_COMPONENT;
@ -887,16 +859,14 @@ Texture CGL33Device::CreateDepthTexture(int width, int height, int depth)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
return result;
}
void CGL33Device::UpdateTexture(const Texture& texture, Math::IntPoint offset, ImageData* data, TexImgFormat format)
{
glActiveTexture(GL_TEXTURE0);
if (texture.id == 0) return;
glBindTexture(GL_TEXTURE_2D, texture.id);
BindTexture(m_freeTexture, texture.id);
PreparedTextureData texData = PrepareTextureData(data, format);
@ -951,18 +921,16 @@ void CGL33Device::SetTexture(int index, const Texture &texture)
{
assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() ));
bool same = m_currentTextures[index].id == texture.id;
if (m_currentTextures[index].id == texture.id)
return;
BindTexture(index, texture.id);
m_currentTextures[index] = texture; // remember the new value
if (same)
return; // nothing to do
glActiveTexture(GL_TEXTURE0 + index);
glBindTexture(GL_TEXTURE_2D, texture.id);
// Params need to be updated for the new bound texture
UpdateTextureParams(index);
UpdateTextureState(index);
}
void CGL33Device::SetTexture(int index, unsigned int textureId)
@ -972,27 +940,25 @@ void CGL33Device::SetTexture(int index, unsigned int textureId)
if (m_currentTextures[index].id == textureId)
return; // nothing to do
m_currentTextures[index].id = textureId;
BindTexture(index, textureId);
glActiveTexture(GL_TEXTURE0 + index);
glBindTexture(GL_TEXTURE_2D, textureId);
m_currentTextures[index].id = textureId;
// Params need to be updated for the new bound texture
UpdateTextureParams(index);
UpdateTextureState(index);
}
void CGL33Device::SetTextureEnabled(int index, bool enabled)
{
assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() ));
bool same = m_texturesEnabled[index] == enabled;
if (m_texturesEnabled[index] == enabled)
return;
m_texturesEnabled[index] = enabled;
if (same)
return; // nothing to do
UpdateRenderingMode();
UpdateTextureState(index);
}
/**
@ -1071,119 +1037,106 @@ void CGL33Device::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode
void CGL33Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount, Color color)
{
if (m_updateLights) UpdateLights();
Vertex* vs = const_cast<Vertex*>(vertices);
unsigned int size = vertexCount * sizeof(Vertex);
DynamicBuffer& buffer = m_dynamicBuffers[0];
DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao);
BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vs, size);
// Start of the buffer, reinitialize binding state
if (offset == 0)
{
// Vertex coordinate
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offsetof(Vertex, coord)));
reinterpret_cast<void*>(offset + offsetof(Vertex, coord)));
// Normal
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offsetof(Vertex, normal)));
reinterpret_cast<void*>(offset + offsetof(Vertex, normal)));
// Color
glDisableVertexAttribArray(2);
glVertexAttrib4fv(2, color.Array());
// Texture coordinate 0
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offsetof(Vertex, texCoord)));
reinterpret_cast<void*>(offset + offsetof(Vertex, texCoord)));
// Texture coordinate 1
glDisableVertexAttribArray(4);
glVertexAttrib2f(4, 0.0f, 0.0f);
}
glVertexAttrib4fv(2, color.Array());
UpdateRenderingMode();
int first = offset / sizeof(Vertex);
glDrawArrays(TranslateGfxPrimitive(type), first, vertexCount);
glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
}
void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, Color color)
{
if (m_updateLights) UpdateLights();
VertexTex2* vs = const_cast<VertexTex2*>(vertices);
unsigned int size = vertexCount * sizeof(VertexTex2);
DynamicBuffer& buffer = m_dynamicBuffers[1];
DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao);
BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vs, size);
if (offset == 0)
{
// Vertex coordinate
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, coord)));
reinterpret_cast<void*>(offset + offsetof(VertexTex2, coord)));
// Normal
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, normal)));
reinterpret_cast<void*>(offset + offsetof(VertexTex2, normal)));
// Color
glDisableVertexAttribArray(2);
glVertexAttrib4fv(2, color.Array());
// Texture coordinate 0
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, texCoord)));
reinterpret_cast<void*>(offset + offsetof(VertexTex2, texCoord)));
// Texture coordinate 1
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, texCoord2)));
}
reinterpret_cast<void*>(offset + offsetof(VertexTex2, texCoord2)));
glVertexAttrib4fv(2, color.Array());
UpdateRenderingMode();
int first = offset / sizeof(VertexTex2);
glDrawArrays(TranslateGfxPrimitive(type), first, vertexCount);
glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
}
void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount)
{
if (m_updateLights) UpdateLights();
VertexCol* vs = const_cast<VertexCol*>(vertices);
unsigned int size = vertexCount * sizeof(VertexCol);
DynamicBuffer& buffer = m_dynamicBuffers[2];
DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao);
BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vs, size);
if (offset == 0)
{
// Vertex coordinate
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexCol),
reinterpret_cast<void*>(offsetof(VertexCol, coord)));
reinterpret_cast<void*>(offset + offsetof(VertexCol, coord)));
// Normal
glDisableVertexAttribArray(1);
@ -1192,7 +1145,7 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i
// Color
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(VertexCol),
reinterpret_cast<void*>(offsetof(VertexCol, color)));
reinterpret_cast<void*>(offset + offsetof(VertexCol, color)));
// Texture coordinate 0
glDisableVertexAttribArray(3);
@ -1201,18 +1154,59 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i
// Texture coordinate 1
glDisableVertexAttribArray(4);
glVertexAttrib2f(4, 0.0f, 0.0f);
glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
}
UpdateRenderingMode();
void CGL33Device::DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount)
{
if (m_updateLights) UpdateLights();
int first = offset / sizeof(VertexCol);
DynamicBuffer& buffer = m_dynamicBuffer;
glDrawArrays(TranslateGfxPrimitive(type), first, vertexCount);
BindVAO(buffer.vao);
BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vertices, size);
// Update vertex attribute bindings
UpdateVertexAttribute(0, format.vertex, offset);
UpdateVertexAttribute(1, format.normal, offset);
UpdateVertexAttribute(2, format.color, offset);
UpdateVertexAttribute(3, format.tex1, offset);
UpdateVertexAttribute(4, format.tex2, offset);
glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
}
void CGL33Device::DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount)
{
if (m_updateLights) UpdateLights();
DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao);
BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vertices, size);
// Update vertex attribute bindings
UpdateVertexAttribute(0, format.vertex, offset);
UpdateVertexAttribute(1, format.normal, offset);
UpdateVertexAttribute(2, format.color, offset);
UpdateVertexAttribute(3, format.tex1, offset);
UpdateVertexAttribute(4, format.tex2, offset);
glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount);
}
void CGL33Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
int first[], int count[], int drawCount, Color color)
{
if (m_updateLights) UpdateLights();
Vertex* vs = const_cast<Vertex*>(vertices);
int vertexCount = 0;
@ -1227,56 +1221,44 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
unsigned int size = vertexCount * sizeof(Vertex);
DynamicBuffer& buffer = m_dynamicBuffers[0];
DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao);
BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vs, size);
if (offset == 0)
{
// Vertex coordinate
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offsetof(Vertex, coord)));
reinterpret_cast<void*>(offset + offsetof(Vertex, coord)));
// Normal
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offsetof(Vertex, normal)));
reinterpret_cast<void*>(offset + offsetof(Vertex, normal)));
// Color
glDisableVertexAttribArray(2);
glVertexAttrib4fv(2, color.Array());
// Texture coordinate 0
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offsetof(Vertex, texCoord)));
reinterpret_cast<void*>(offset + offsetof(Vertex, texCoord)));
// Texture coordinate 1
glDisableVertexAttribArray(4);
glVertexAttrib2f(4, 0.0f, 0.0f);
}
glVertexAttrib4fv(2, color.Array());
UpdateRenderingMode();
int firstOffset = offset / sizeof(Vertex);
for (int i = 0; i < drawCount; i++)
first[i] += firstOffset;
glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount);
for (int i = 0; i < drawCount; i++)
first[i] -= firstOffset;
}
void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices,
int first[], int count[], int drawCount, Color color)
{
if (m_updateLights) UpdateLights();
VertexTex2* vs = const_cast<VertexTex2*>(vertices);
int vertexCount = 0;
@ -1291,57 +1273,45 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices,
unsigned int size = vertexCount * sizeof(VertexTex2);
DynamicBuffer& buffer = m_dynamicBuffers[1];
DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao);
BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vs, size);
if (offset == 0)
{
// Vertex coordinate
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, coord)));
reinterpret_cast<void*>(offset + offsetof(VertexTex2, coord)));
// Normal
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, normal)));
reinterpret_cast<void*>(offset + offsetof(VertexTex2, normal)));
// Color
glDisableVertexAttribArray(2);
glVertexAttrib4fv(2, color.Array());
// Texture coordinate 0
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, texCoord)));
reinterpret_cast<void*>(offset + offsetof(VertexTex2, texCoord)));
// Texture coordinate 1
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, texCoord2)));
}
glVertexAttrib4fv(2, color.Array());
UpdateRenderingMode();
int firstOffset = offset / sizeof(VertexTex2);
for (int i = 0; i < drawCount; i++)
first[i] += firstOffset;
reinterpret_cast<void*>(offset + offsetof(VertexTex2, texCoord2)));
glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount);
for (int i = 0; i < drawCount; i++)
first[i] -= firstOffset;
}
void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices,
int first[], int count[], int drawCount)
{
if (m_updateLights) UpdateLights();
VertexCol* vs = const_cast<VertexCol*>(vertices);
int vertexCount = 0;
@ -1356,19 +1326,17 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices,
unsigned int size = vertexCount * sizeof(VertexCol);
DynamicBuffer& buffer = m_dynamicBuffers[2];
DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao);
BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vs, size);
if (offset == 0)
{
// Vertex coordinate
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexCol),
reinterpret_cast<void*>(offsetof(VertexCol, coord)));
reinterpret_cast<void*>(offset + offsetof(VertexCol, coord)));
// Normal
glDisableVertexAttribArray(1);
@ -1377,7 +1345,7 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices,
// Color
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(VertexCol),
reinterpret_cast<void*>(offsetof(VertexCol, color)));
reinterpret_cast<void*>(offset + offsetof(VertexCol, color)));
// Texture coordinate 0
glDisableVertexAttribArray(3);
@ -1386,19 +1354,8 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices,
// Texture coordinate 1
glDisableVertexAttribArray(4);
glVertexAttrib2f(4, 0.0f, 0.0f);
}
UpdateRenderingMode();
int firstOffset = offset / sizeof(VertexCol);
for (int i = 0; i < drawCount; i++)
first[i] += firstOffset;
glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount);
for (int i = 0; i < drawCount; i++)
first[i] -= firstOffset;
}
unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount)
@ -1716,14 +1673,14 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
void CGL33Device::DrawStaticBuffer(unsigned int bufferId)
{
if (m_updateLights) UpdateLights();
auto it = m_vboObjects.find(bufferId);
if (it == m_vboObjects.end())
return;
VertexBufferInfo &info = (*it).second;
UpdateRenderingMode();
BindVAO(info.vao);
GLenum mode = TranslateGfxPrimitive(info.primitiveType);
@ -1851,7 +1808,9 @@ void CGL33Device::SetRenderState(RenderState state, bool enabled)
{
m_lighting = enabled;
glUniform1i(m_uni->lightingEnabled, enabled ? 1 : 0);
m_updateLights = true;
//glUniform1i(m_uni->lightingEnabled, enabled ? 1 : 0);
return;
}
@ -1977,13 +1936,9 @@ void CGL33Device::CopyFramebufferToTexture(Texture& texture, int xOffset, int yO
{
if (texture.id == 0) return;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.id);
BindTexture(m_freeTexture, texture.id);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height);
// Restore previous texture
glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
}
std::unique_ptr<CFrameBufferPixels> CGL33Device::GetFrameBufferPixels() const
@ -2029,16 +1984,52 @@ void CGL33Device::DeleteFramebuffer(std::string name)
}
}
void CGL33Device::UpdateRenderingMode()
inline void CGL33Device::UpdateTextureState(int index)
{
bool enabled = m_texturesEnabled[0] && m_currentTextures[0].id != 0;
glUniform1i(m_uni->textureEnabled[0], enabled ? 1 : 0);
bool enabled = m_texturesEnabled[index] && (m_currentTextures[index].id != 0);
glUniform1i(m_uni->textureEnabled[index], enabled ? 1 : 0);
}
enabled = m_texturesEnabled[1] && m_currentTextures[1].id != 0;
glUniform1i(m_uni->textureEnabled[1], enabled ? 1 : 0);
void CGL33Device::UpdateLights()
{
m_updateLights = false;
enabled = m_texturesEnabled[2] && m_currentTextures[2].id != 0;
glUniform1i(m_uni->textureEnabled[2], enabled ? 1 : 0);
// If not in normal rendering mode, return immediately
if (m_mode != 0) return;
// Lighting enabled
if (m_lighting)
{
int index = 0;
// Iterate all lights
for (unsigned int i = 0; i < m_lights.size(); i++)
{
// If disabled, ignore and continue
if (!m_lightsEnabled[i]) continue;
// If not directional, ignore and continue
if (m_lights[i].type != LIGHT_DIRECTIONAL) continue;
Light &light = m_lights[i];
LightLocations &uni = m_uni->lights[index];
glUniform4fv(uni.ambient, 1, light.ambient.Array());
glUniform4fv(uni.diffuse, 1, light.diffuse.Array());
glUniform4fv(uni.specular, 1, light.specular.Array());
glUniform4f(uni.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f);
index++;
}
glUniform1i(m_uni->lightCount, index);
}
// Lighting disabled
else
{
glUniform1i(m_uni->lightCount, 0);
}
}
inline void CGL33Device::BindVBO(GLuint vbo)
@ -2057,7 +2048,13 @@ inline void CGL33Device::BindVAO(GLuint vao)
m_currentVAO = vao;
}
unsigned int CGL33Device::UploadVertexData(DynamicBuffer& buffer, void* data, unsigned int size)
inline void CGL33Device::BindTexture(int index, GLuint texture)
{
glActiveTexture(GL_TEXTURE0 + index);
glBindTexture(GL_TEXTURE_2D, texture);
}
unsigned int CGL33Device::UploadVertexData(DynamicBuffer& buffer, const void* data, unsigned int size)
{
unsigned int nextOffset = buffer.offset + size;
@ -2095,6 +2092,25 @@ unsigned int CGL33Device::UploadVertexData(DynamicBuffer& buffer, void* data, un
return currentOffset;
}
void CGL33Device::UpdateVertexAttribute(int index, const VertexAttribute &attribute, int offset)
{
if (attribute.enabled)
{
glEnableVertexAttribArray(index);
glVertexAttribPointer(index,
attribute.size,
TranslateType(attribute.type),
attribute.normalized ? GL_TRUE : GL_FALSE,
attribute.stride,
reinterpret_cast<void*>(offset + attribute.offset));
}
else
{
glDisableVertexAttribArray(index);
glVertexAttrib4fv(index, attribute.values);
}
}
bool CGL33Device::IsAnisotropySupported()
{
return m_capabilities.anisotropySupported;

View File

@ -115,6 +115,11 @@ public:
void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override;
virtual void DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount) override;
virtual void DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount) override;
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override;
virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount,
@ -193,16 +198,22 @@ public:
private:
//! Updates the texture params for given texture stage
void UpdateTextureParams(int index);
//! Updates rendering mode
void UpdateRenderingMode();
//! Updates texture state
inline void UpdateTextureState(int index);
//! Update light parameters
void UpdateLights();
//! Binds VBO
inline void BindVBO(GLuint vbo);
//! Binds VAO
inline void BindVAO(GLuint vao);
//! Binds texture
inline void BindTexture(int index, GLuint texture);
//! Uploads data to dynamic buffer and returns offset to it
unsigned int UploadVertexData(DynamicBuffer& buffer, void* data, unsigned int size);
unsigned int UploadVertexData(DynamicBuffer& buffer, const void* data, unsigned int size);
inline void UpdateVertexAttribute(int index, const VertexAttribute &attribute, int offset);
private:
//! Current config
@ -226,6 +237,8 @@ private:
//! Whether lighting is enabled
bool m_lighting = false;
//! true means that light update is needed
bool m_updateLights = false;
//! Current lights
std::vector<Light> m_lights;
//! Current lights enable status
@ -240,6 +253,8 @@ private:
//! Set of all created textures
std::set<Texture> m_allTextures;
//! Free texture unit
const int m_freeTexture = 3;
//! Type of vertex structure
enum VertexType
@ -283,7 +298,7 @@ private:
//! Shader program for shadow rendering
GLuint m_shadowProgram = 0;
DynamicBuffer m_dynamicBuffers[3];
DynamicBuffer m_dynamicBuffer;
//! Current mode
unsigned int m_mode = 0;

View File

@ -335,8 +335,10 @@ GLenum TranslateGfxPrimitive(PrimitiveType type)
case PRIMITIVE_POINTS: flag = GL_POINTS; break;
case PRIMITIVE_LINES: flag = GL_LINES; break;
case PRIMITIVE_LINE_STRIP: flag = GL_LINE_STRIP; break;
case PRIMITIVE_LINE_LOOP: flag = GL_LINE_LOOP; break;
case PRIMITIVE_TRIANGLES: flag = GL_TRIANGLES; break;
case PRIMITIVE_TRIANGLE_STRIP: flag = GL_TRIANGLE_STRIP; break;
case PRIMITIVE_TRIANGLE_FAN: flag = GL_TRIANGLE_FAN; break;
default: assert(false); break;
}
return flag;
@ -441,6 +443,23 @@ GLenum TranslateTextureCoordinateGen(int index)
return textureCoordGen[index];
}
GLenum TranslateType(Type type)
{
switch (type)
{
case Type::BYTE: return GL_BYTE;
case Type::UBYTE: return GL_UNSIGNED_BYTE;
case Type::SHORT: return GL_SHORT;
case Type::USHORT: return GL_UNSIGNED_SHORT;
case Type::INT: return GL_INT;
case Type::UINT: return GL_UNSIGNED_INT;
case Type::HALF: return GL_HALF_FLOAT;
case Type::FLOAT: return GL_FLOAT;
case Type::DOUBLE: return GL_DOUBLE;
default: return 0;
}
}
std::string lastShaderError;
std::string GetLastShaderError()

View File

@ -93,6 +93,8 @@ GLenum TranslateTextureCoordinate(int index);
GLenum TranslateTextureCoordinateGen(int index);
GLenum TranslateType(Type type);
std::string GetLastShaderError();
GLint LoadShader(GLint type, const char* filename);
@ -192,8 +194,8 @@ struct UniformLocations
//! Shadow color
GLint shadowColor = -1;
//! true enables lighting
GLint lightingEnabled = -1;
// Number of enabled lights
GLint lightCount = -1;
//! Ambient color
GLint ambientColor = -1;
//! Diffuse color

View File

@ -19,6 +19,8 @@
// FRAGMENT SHADER - NORMAL MODE
#version 120
#define CONFIG_QUALITY_SHADOWS 1
uniform sampler2D uni_PrimaryTexture;
uniform sampler2D uni_SecondaryTexture;
uniform sampler2DShadow uni_ShadowTexture;
@ -34,6 +36,26 @@ uniform vec4 uni_FogColor;
uniform float uni_ShadowColor;
struct LightParams
{
vec4 Position;
vec4 Ambient;
vec4 Diffuse;
vec4 Specular;
};
struct Material
{
vec4 ambient;
vec4 diffuse;
vec4 specular;
};
uniform Material uni_Material;
uniform int uni_LightCount;
uniform LightParams uni_Light[4];
varying float pass_Distance;
varying vec4 pass_Color;
varying vec3 pass_Normal;
@ -47,6 +69,55 @@ void main()
{
vec4 color = pass_Color;
if (uni_LightCount > 0)
{
vec4 ambient = vec4(0.0f);
vec4 diffuse = vec4(0.0f);
vec4 specular = vec4(0.0f);
vec3 normal = normalize(pass_Normal);
for (int i = 0; i < uni_LightCount; i++)
{
LightParams light = uni_Light[i];
vec3 lightDirection = light.Position.xyz;
vec3 reflectDirection = -reflect(lightDirection, normal);
float diffuseComponent = clamp(dot(normal, lightDirection), 0.0f, 1.0f);
float specularComponent = clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f);
ambient += light.Ambient;
diffuse += diffuseComponent * light.Diffuse;
specular += specularComponent * light.Specular;
}
float shadow = 1.0f;
if (uni_TextureEnabled[2])
{
#ifdef CONFIG_QUALITY_SHADOWS
float offset = 0.00025f;
float value = (1.0f / 5.0f) * (shadow2D(uni_ShadowTexture, pass_TexCoord2).x
+ shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( offset, 0.0f, 0.0f)).x
+ shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3(-offset, 0.0f, 0.0f)).x
+ shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( 0.0f, offset, 0.0f)).x
+ shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( 0.0f, -offset, 0.0f)).x);
shadow = mix(uni_ShadowColor, 1.0f, value);
#else
shadow = mix(uni_ShadowColor, 1.0f, shadow2D(uni_ShadowTexture, pass_TexCoord2).x);
#endif
}
vec4 result = ambient * uni_Material.ambient
+ diffuse * uni_Material.diffuse * shadow
+ specular * uni_Material.specular * shadow;
color = clamp(vec4(result.rgb, 1.0f), 0.0f, 1.0f);
}
if (uni_TextureEnabled[0])
{
color = color * texture2D(uni_PrimaryTexture, pass_TexCoord0);
@ -57,16 +128,6 @@ void main()
color = color * texture2D(uni_SecondaryTexture, pass_TexCoord1);
}
if (uni_TextureEnabled[2])
{
vec3 normal = pass_Normal * (2.0f * gl_Color.x - 1.0f);
if (dot(normal, const_LightDirection) < 0.0f)
color.rgb *= uni_ShadowColor;
else
color.rgb *= mix(uni_ShadowColor, 1.0f, shadow2D(uni_ShadowTexture, pass_TexCoord2).x);
}
if (uni_FogEnabled)
{
float interpolate = (pass_Distance - uni_FogRange.x) / (uni_FogRange.y - uni_FogRange.x);

View File

@ -25,33 +25,6 @@ uniform mat4 uni_ModelMatrix;
uniform mat4 uni_ShadowMatrix;
uniform mat4 uni_NormalMatrix;
struct LightParams
{
bool Enabled;
int Type;
vec4 Position;
vec4 Ambient;
vec4 Diffuse;
vec4 Specular;
float Shininess;
vec3 Attenuation;
vec3 SpotDirection;
float SpotCutoff;
float SpotExponent;
};
struct Material
{
vec4 ambient;
vec4 diffuse;
vec4 specular;
};
uniform Material uni_Material;
uniform bool uni_LightingEnabled;
uniform LightParams uni_Light[8];
varying float pass_Distance;
varying vec4 pass_Color;
varying vec3 pass_Normal;
@ -65,75 +38,11 @@ void main()
vec4 eyeSpace = uni_ViewMatrix * position;
vec4 shadowCoord = uni_ShadowMatrix * position;
vec4 color = gl_Color;
vec3 normal = normalize((uni_NormalMatrix * vec4(gl_Normal, 0.0f)).xyz);
if (uni_LightingEnabled)
{
vec4 ambient = vec4(0.0f);
vec4 diffuse = vec4(0.0f);
vec4 specular = vec4(0.0f);
for (int i = 0; i < 8; i++)
{
if (uni_Light[i].Enabled)
{
LightParams light = uni_Light[i];
vec3 lightDirection = light.Position.xyz;
float atten = 1.0f;
if (light.Position.w > 0.5f)
{
float dist = distance(light.Position.xyz, position.xyz);
float atten = 1.0f / dot(light.Attenuation,
vec3(1.0f, dist, dist * dist));
lightDirection = normalize(light.Position.xyz - position.xyz);
}
float spot = 1.0f;
if (light.SpotCutoff > 0.0f)
{
float cone = dot(light.SpotDirection, lightDirection);
if (cone > light.SpotCutoff)
{
spot = pow(cone, light.SpotExponent);
}
else
{
continue;
}
}
vec3 reflectDirection = -reflect(lightDirection, normal);
float component = atten * spot;
float diffuseComponent = clamp(dot(normal, lightDirection), 0.0f, 1.0f);
float specularComponent = clamp(pow(dot(normal, lightDirection + reflectDirection), light.Shininess), 0.0f, 1.0f);
ambient += component * light.Ambient * uni_Material.ambient;
diffuse += component * diffuseComponent * light.Diffuse * uni_Material.diffuse;
specular += component * specularComponent * light.Specular * uni_Material.specular;
}
}
vec4 result = ambient + diffuse + specular;
color = clamp(vec4(result.rgb, uni_Material.diffuse), 0.0f, 1.0f);
}
gl_Position = uni_ProjectionMatrix * eyeSpace;
gl_FrontColor = vec4(1.0f);
gl_BackColor = vec4(0.0f);
pass_Color = gl_Color;
pass_Normal = normalize((uni_NormalMatrix * vec4(gl_Normal, 0.0f)).xyz);
pass_Distance = abs(eyeSpace.z / eyeSpace.w);
pass_Color = color;
pass_Normal = normal;
pass_TexCoord0 = gl_MultiTexCoord0.st;
pass_TexCoord1 = gl_MultiTexCoord1.st;
pass_TexCoord2 = shadowCoord.xyz / shadowCoord.w;

View File

@ -20,6 +20,8 @@
// FRAGMENT SHADER - NORMAL MODE
#version 330 core
#define CONFIG_QUALITY_SHADOWS 1
uniform sampler2D uni_PrimaryTexture;
uniform sampler2D uni_SecondaryTexture;
uniform sampler2DShadow uni_ShadowTexture;
@ -37,11 +39,27 @@ uniform float uni_ShadowColor;
uniform bool uni_AlphaTestEnabled;
uniform float uni_AlphaReference;
struct LightParams
{
vec4 Position;
vec4 Ambient;
vec4 Diffuse;
vec4 Specular;
};
uniform vec4 uni_AmbientColor;
uniform vec4 uni_DiffuseColor;
uniform vec4 uni_SpecularColor;
uniform int uni_LightCount;
uniform LightParams uni_Light[4];
in VertexData
{
vec4 Color;
vec2 TexCoord0;
vec2 TexCoord1;
vec3 Normal;
vec4 ShadowCoord;
vec4 LightColor;
float Distance;
@ -53,6 +71,53 @@ void main()
{
vec4 color = data.Color;
if (uni_LightCount > 0)
{
vec4 ambient = vec4(0.0f);
vec4 diffuse = vec4(0.0f);
vec4 specular = vec4(0.0f);
vec3 normal = normalize(data.Normal);
for (int i = 0; i < uni_LightCount; i++)
{
vec3 lightDirection = uni_Light[i].Position.xyz;
vec3 reflectDirection = -reflect(lightDirection, normal);
ambient += uni_Light[i].Ambient;
diffuse += clamp(dot(normal, lightDirection), 0.0f, 1.0f)
* uni_Light[i].Diffuse;
specular += clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f)
* uni_Light[i].Specular;
}
float shadow = 1.0f;
if (uni_ShadowTextureEnabled)
{
#ifdef CONFIG_QUALITY_SHADOWS
float offset = 0.00025f;
float value = (1.0f / 5.0f) * (texture(uni_ShadowTexture, data.ShadowCoord.xyz)
+ texture(uni_ShadowTexture, data.ShadowCoord.xyz + vec3( offset, 0.0f, 0.0f))
+ texture(uni_ShadowTexture, data.ShadowCoord.xyz + vec3(-offset, 0.0f, 0.0f))
+ texture(uni_ShadowTexture, data.ShadowCoord.xyz + vec3( 0.0f, offset, 0.0f))
+ texture(uni_ShadowTexture, data.ShadowCoord.xyz + vec3( 0.0f, -offset, 0.0f)));
shadow = mix(uni_ShadowColor, 1.0f, value);
#else
shadow = mix(uni_ShadowColor, 1.0f, texture(uni_ShadowTexture, data.ShadowCoord.xyz));
#endif
}
vec4 result = uni_AmbientColor * ambient
+ uni_DiffuseColor * diffuse * shadow
+ uni_SpecularColor * specular * shadow;
color = vec4(min(vec3(1.0f), result.rgb), 1.0f);
}
if (uni_PrimaryTextureEnabled)
{
color = color * texture(uni_PrimaryTexture, data.TexCoord0);
@ -63,11 +128,6 @@ void main()
color = color * texture(uni_SecondaryTexture, data.TexCoord1);
}
if (uni_ShadowTextureEnabled)
{
color = color * mix(uni_ShadowColor, 1.0f, texture(uni_ShadowTexture, data.ShadowCoord.xyz));
}
if (uni_FogEnabled)
{
float interpolate = (data.Distance - uni_FogRange.x) / (uni_FogRange.y - uni_FogRange.x);

View File

@ -20,24 +20,6 @@
// VERTEX SHADER - NORMAL MODE
#version 330 core
struct LightParams
{
bool Enabled;
vec4 Position;
vec4 Ambient;
vec4 Diffuse;
vec4 Specular;
float Shininess;
vec3 Attenuation;
};
uniform vec4 uni_AmbientColor;
uniform vec4 uni_DiffuseColor;
uniform vec4 uni_SpecularColor;
uniform bool uni_LightingEnabled;
uniform LightParams uni_Light[8];
uniform mat4 uni_ProjectionMatrix;
uniform mat4 uni_ViewMatrix;
uniform mat4 uni_ModelMatrix;
@ -55,6 +37,7 @@ out VertexData
vec4 Color;
vec2 TexCoord0;
vec2 TexCoord1;
vec3 Normal;
vec4 ShadowCoord;
vec4 LightColor;
float Distance;
@ -70,58 +53,7 @@ void main()
data.Color = in_Color;
data.TexCoord0 = in_TexCoord0;
data.TexCoord1 = in_TexCoord1;
data.Normal = normalize((uni_NormalMatrix * vec4(in_Normal, 0.0f)).xyz);
data.ShadowCoord = vec4(shadowCoord.xyz / shadowCoord.w, 1.0f);
data.Distance = abs(eyeSpace.z);
vec4 color = in_Color;
if (uni_LightingEnabled)
{
vec4 ambient = vec4(0.0f);
vec4 diffuse = vec4(0.0f);
vec4 specular = vec4(0.0f);
vec3 normal = normalize((uni_NormalMatrix * vec4(in_Normal, 0.0f)).xyz);
for(int i=0; i<8; i++)
{
if(uni_Light[i].Enabled)
{
vec3 lightDirection = vec3(0.0f);
float atten;
// Directional light
if(uni_Light[i].Position[3] == 0.0f)
{
lightDirection = uni_Light[i].Position.xyz;
atten = 1.0f;
}
// Point light
else
{
vec3 lightDirection = normalize(uni_Light[i].Position.xyz - position.xyz);
float dist = distance(uni_Light[i].Position.xyz, position.xyz);
atten = 1.0f / (uni_Light[i].Attenuation.x
+ uni_Light[i].Attenuation.y * dist
+ uni_Light[i].Attenuation.z * dist * dist);
}
vec3 reflectDirection = -reflect(lightDirection, normal);
ambient += uni_Light[i].Ambient;
diffuse += atten * clamp(dot(normal, lightDirection), 0.0f, 1.0f) * uni_Light[i].Diffuse;
specular += atten * clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f) * uni_Light[i].Specular;
}
}
vec4 result = uni_AmbientColor * ambient
+ uni_DiffuseColor * diffuse
+ uni_SpecularColor * specular;
color.rgb = min(vec3(1.0f), result.rgb);
color.a = 1.0f; //min(1.0f, 1.0f);
data.Color = color;
}
}

View File

@ -467,6 +467,8 @@ ObjectType CLevelParserParam::ToObjectType(std::string value)
if (value == "Barrier1" ) return OBJECT_BARRIER1;
if (value == "Barrier2" ) return OBJECT_BARRIER2;
if (value == "Barrier3" ) return OBJECT_BARRIER3;
if (value == "Barricade0" ) return OBJECT_BARRICADE0;
if (value == "Barricade1" ) return OBJECT_BARRICADE1;
if (value == "Teen0" ) return OBJECT_TEEN0;
if (value == "Teen1" ) return OBJECT_TEEN1;
if (value == "Teen2" ) return OBJECT_TEEN2;
@ -662,6 +664,8 @@ const std::string CLevelParserParam::FromObjectType(ObjectType value)
if (value == OBJECT_BARRIER1 ) return "Barrier1";
if (value == OBJECT_BARRIER2 ) return "Barrier2";
if (value == OBJECT_BARRIER3 ) return "Barrier3";
if (value == OBJECT_BARRICADE0 ) return "Barricade0";
if (value == OBJECT_BARRICADE1 ) return "Barricade1";
if (value == OBJECT_TEEN0 ) return "Teen0";
if (value == OBJECT_TEEN1 ) return "Teen1";
if (value == OBJECT_TEEN2 ) return "Teen2";

View File

@ -133,7 +133,7 @@ std::string CPlayerProfile::GetLastName()
{
std::string name;
if(!GetConfigFile().GetStringProperty("Gamer", "LastName", name))
if(!GetConfigFile().GetStringProperty("Gamer", "LastName", name) || name.empty())
GetResource(RES_TEXT, RT_NAME_DEFAULT, name);
return name;

View File

@ -55,6 +55,7 @@
#include "level/mainmovie.h"
#include "level/player_profile.h"
#include "level/scene_conditions.h"
#include "level/scoreboard.h"
#include "level/parser/parser.h"
@ -202,8 +203,8 @@ CRobotMain::CRobotMain()
m_editLock = false;
m_editFull = false;
m_hilite = false;
m_selectInsect = false;
m_showSoluce = false;
m_cheatSelectInsect = false;
m_cheatShowSoluce = false;
m_codeBattleInit = false;
m_codeBattleStarted = false;
@ -211,14 +212,14 @@ CRobotMain::CRobotMain()
m_teamNames.clear();
#if DEV_BUILD
m_showAll = true; // for development
m_cheatAllMission = true; // for development
#else
m_showAll = false;
m_cheatAllMission = false;
#endif
m_cheatRadar = false;
m_fixScene = false;
m_trainerPilot = false;
m_cheatTrainerPilot = false;
m_friendAim = false;
m_resetCreate = false;
m_shortCut = true;
@ -451,7 +452,7 @@ void CRobotMain::ChangePhase(Phase phase)
m_lightning->Flush();
m_planet->Flush();
m_interface->Flush();
FlushNewScriptName();
m_newScriptName.clear();
m_sound->SetListener(Math::Vector(0.0f, 0.0f, 0.0f), Math::Vector(0.0f, 0.0f, 1.0f));
m_sound->StopAll();
m_camera->SetType(Gfx::CAM_TYPE_NULL);
@ -763,6 +764,7 @@ bool CRobotMain::ProcessEvent(Event &event)
m_interface->SetFocus(pe);
if (m_phase == PHASE_SIMUL) m_cmdEditPause = m_pause->ActivatePause(PAUSE_ENGINE);
m_cmdEdit = true;
m_commandHistoryIndex = -1; // no element selected in command history
}
return false;
}
@ -777,6 +779,28 @@ bool CRobotMain::ProcessEvent(Event &event)
}
}
// Browse forward command history with UP key
if (event.type == EVENT_KEY_DOWN &&
event.GetData<KeyEventData>()->key == KEY(UP) && m_cmdEdit)
{
Ui::CEdit* pe = static_cast<Ui::CEdit*>(m_interface->SearchControl(EVENT_CMD));
if (pe == nullptr) return false;
std::string cmd = GetNextFromCommandHistory();
if (!cmd.empty()) pe->SetText(cmd);
return false;
}
// Browse backward command history with DOWN key
if (event.type == EVENT_KEY_DOWN &&
event.GetData<KeyEventData>()->key == KEY(DOWN) && m_cmdEdit)
{
Ui::CEdit* pe = static_cast<Ui::CEdit*>(m_interface->SearchControl(EVENT_CMD));
if (pe == nullptr) return false;
std::string cmd = GetPreviousFromCommandHistory();
if (!cmd.empty()) pe->SetText(cmd);
return false;
}
if (event.type == EVENT_KEY_DOWN &&
event.GetData<KeyEventData>()->key == KEY(RETURN) && m_cmdEdit)
{
@ -793,6 +817,7 @@ bool CRobotMain::ProcessEvent(Event &event)
m_cmdEditPause = nullptr;
}
ExecuteCmd(cmd);
PushToCommandHistory(cmd);
m_cmdEdit = false;
return false;
}
@ -922,7 +947,7 @@ bool CRobotMain::ProcessEvent(Event &event)
}
if (data->slot == INPUT_SLOT_HUMAN)
{
SelectHuman();
SelectObject(SearchHuman());
}
if (data->slot == INPUT_SLOT_NEXT && ((event.kmodState & KEY_MOD(CTRL)) != 0))
{
@ -1159,7 +1184,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
if (cmd == "trainerpilot")
{
m_trainerPilot = !m_trainerPilot;
m_cheatTrainerPilot = !m_cheatTrainerPilot;
return;
}
@ -1410,20 +1435,20 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
if (cmd == "selectinsect")
{
m_selectInsect = !m_selectInsect;
m_cheatSelectInsect = !m_cheatSelectInsect;
return;
}
if (cmd == "showsoluce")
{
m_showSoluce = !m_showSoluce;
m_cheatShowSoluce = !m_cheatShowSoluce;
m_ui->ShowSoluceUpdate();
return;
}
if (cmd == "allmission")
{
m_showAll = !m_showAll;
m_cheatAllMission = !m_cheatAllMission;
m_ui->AllMissionUpdate();
return;
}
@ -1763,20 +1788,17 @@ void CRobotMain::StopDisplayVisit()
//! Updates all the shortcuts
void CRobotMain::UpdateShortcuts()
{
m_short->UpdateShortcuts();
}
//! Returns the object that default was select after the creation of a scene
CObject* CRobotMain::GetSelectObject()
{
if (m_selectObject != nullptr) return m_selectObject;
return SearchHuman();
}
//! Deselects everything, and returns the object that was selected
CObject* CRobotMain::DeselectAll()
{
CObject* prev = nullptr;
@ -1833,17 +1855,8 @@ void CRobotMain::SelectOneObject(CObject* obj, bool displayError)
{
m_camera->SetType(Gfx::CAM_TYPE_BACK);
}
CObject* toto = SearchToto();
if (toto != nullptr)
{
assert(toto->Implements(ObjectInterfaceType::Movable));
CMotionToto* mt = static_cast<CMotionToto*>(dynamic_cast<CMovableObject*>(toto)->GetMotion());
mt->SetLinkType(type);
}
}
//! Selects the object aimed by the mouse
bool CRobotMain::SelectObject(CObject* obj, bool displayError)
{
if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT)
@ -1851,7 +1864,8 @@ bool CRobotMain::SelectObject(CObject* obj, bool displayError)
if (m_movieLock || m_editLock) return false;
if (m_movie->IsExist()) return false;
if (obj != nullptr && !IsSelectable(obj)) return false;
if (obj != nullptr &&
(!obj->Implements(ObjectInterfaceType::Controllable) || !(dynamic_cast<CControllableObject*>(obj)->GetSelectable() || m_cheatSelectInsect))) return false;
if (m_missionType == MISSION_CODE_BATTLE && m_codeBattleStarted && m_codeBattleSpectator)
{
@ -1882,7 +1896,6 @@ bool CRobotMain::SelectObject(CObject* obj, bool displayError)
return true;
}
//! Deselects the selected object
bool CRobotMain::DeselectObject()
{
DeselectAll();
@ -1918,49 +1931,11 @@ void CRobotMain::DeleteAllObjects()
m_objMan->DeleteAllObjects();
}
//! Selects the human
void CRobotMain::SelectHuman()
{
SelectObject(SearchHuman());
}
//! Returns the object human
CObject* CRobotMain::SearchHuman()
{
return m_objMan->FindNearest(nullptr, OBJECT_HUMAN);
}
//! Returns the object toto
CObject* CRobotMain::SearchToto()
{
return m_objMan->FindNearest(nullptr, OBJECT_TOTO);
}
//! Returns the nearest selectable object from a given position
CObject* CRobotMain::SearchNearest(Math::Vector pos, CObject* exclu)
{
float min = 100000.0f;
CObject* best = nullptr;
for (CObject* obj : m_objMan->GetAllObjects())
{
if (obj == exclu) continue;
if (!IsSelectable(obj)) continue;
ObjectType type = obj->GetType();
if (type == OBJECT_TOTO) continue;
Math::Vector oPos = obj->GetPosition();
float dist = Math::DistanceProjected(oPos, pos);
if (dist < min)
{
min = dist;
best = obj;
}
}
return best;
}
//! Returns the selected object
CObject* CRobotMain::GetSelect()
{
for (CObject* obj : m_objMan->GetAllObjects())
@ -2019,30 +1994,6 @@ CObject* CRobotMain::DetectObject(Math::Point pos)
return nullptr;
}
//! Indicates whether an object is selectable
// TODO: Refactor this, calling CControllableObject::GetSelectable should always be enough
bool CRobotMain::IsSelectable(CObject* obj)
{
if (obj->GetType() == OBJECT_TOTO) return true;
if (!obj->Implements(ObjectInterfaceType::Controllable)) return false;
if (!m_selectInsect)
{
// TODO: Some function in CControllableObject
if ( obj->GetType() == OBJECT_MOTHER ||
obj->GetType() == OBJECT_ANT ||
obj->GetType() == OBJECT_SPIDER ||
obj->GetType() == OBJECT_BEE ||
obj->GetType() == OBJECT_WORM ||
obj->GetType() == OBJECT_MOBILEtg )
{
return false;
}
}
return dynamic_cast<CControllableObject*>(obj)->GetSelectable();
}
//! Deletes the selected object
bool CRobotMain::DestroySelectedObject()
@ -2136,10 +2087,13 @@ void CRobotMain::HiliteObject(Math::Point pos)
}
}
if (IsSelectable(obj))
if (obj->Implements(ObjectInterfaceType::Controllable) && (dynamic_cast<CControllableObject*>(obj)->GetSelectable() || m_cheatSelectInsect))
{
assert(obj->Implements(ObjectInterfaceType::Controllable));
if (dynamic_cast<CControllableObject*>(obj)->GetSelectable())
{
// Don't highlight objects that would not be selectable without selectinsect
dynamic_cast<CControllableObject*>(obj)->SetHighlight(true);
}
m_map->SetHighlight(obj);
m_short->SetHighlight(obj);
m_hilite = true;
@ -2565,7 +2519,7 @@ bool CRobotMain::EventFrame(const Event &event)
if (m_phase == PHASE_SIMUL)
{
if (!m_editLock)
if (!m_editLock && !m_engine->GetPause())
{
CheckEndMission(true);
UpdateAudio(true);
@ -2589,12 +2543,11 @@ bool CRobotMain::EventFrame(const Event &event)
if (m_lostDelay <= 0.0f)
{
if (m_movieLock)
m_winDelay = 1.0f;
m_lostDelay = 1.0f;
else
m_eventQueue->AddEvent(Event(EVENT_LOST));
}
}
}
if (GetMissionType() == MISSION_CODE_BATTLE)
{
@ -2609,12 +2562,16 @@ bool CRobotMain::EventFrame(const Event &event)
if (!m_codeBattleStarted && m_userPause == nullptr)
{
m_codeBattleStarted = true;
ApplyCodeBattleInterface();
CreateCodeBattleInterface();
SetCodeBattleSpectatorMode(true);
m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE));
}
UpdateCodeBattleInterface();
}
}
return true;
@ -2672,7 +2629,6 @@ bool CRobotMain::EventObject(const Event &event)
//! Load the scene for the character
void CRobotMain::ScenePerso()
{
DeleteAllObjects(); // removes all the current 3D Scene
@ -2743,6 +2699,8 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
m_endTakeResearch = 0;
m_endTakeWinDelay = 2.0f;
m_endTakeLostDelay = 2.0f;
m_teamFinished.clear();
m_scoreboard.reset();
m_globalMagnifyDamage = 1.0f;
m_obligatoryTokens.clear();
m_mapShow = true;
@ -3365,6 +3323,9 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
assert(m_controller->Implements(ObjectInterfaceType::Programmable));
assert(m_controller->Implements(ObjectInterfaceType::ProgramStorage));
assert(m_controller->Implements(ObjectInterfaceType::Old));
dynamic_cast<COldObject*>(m_controller)->SetCheckToken(false);
if (line->GetParam("script")->IsDefined())
{
CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(m_controller);
@ -3600,6 +3561,34 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
continue;
}
if (line->GetCommand() == "Scoreboard" && !resetObject)
{
if (line->GetParam("enable")->AsBool(false))
{
// Create the scoreboard
m_scoreboard = MakeUnique<CScoreboard>();
}
continue;
}
if (line->GetCommand() == "ScoreboardKillRule" && !resetObject)
{
if (!m_scoreboard)
throw CLevelParserException("ScoreboardKillRule encountered but scoreboard is not enabled");
auto rule = MakeUnique<CScoreboard::CScoreboardKillRule>();
rule->Read(line.get());
m_scoreboard->AddKillRule(std::move(rule));
continue;
}
if (line->GetCommand() == "ScoreboardEndTakeRule" && !resetObject)
{
if (!m_scoreboard)
throw CLevelParserException("ScoreboardEndTakeRule encountered but scoreboard is not enabled");
auto rule = MakeUnique<CScoreboard::CScoreboardEndTakeRule>();
rule->Read(line.get());
m_scoreboard->AddEndTakeRule(std::move(rule));
continue;
}
if (line->GetCommand() == "ObligatoryToken" && !resetObject)
{
std::string token = line->GetParam("text")->AsString();
@ -3649,7 +3638,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
if (line->GetCommand() == "NewScript" && !resetObject)
{
AddNewScriptName(line->GetParam("type")->AsObjectType(OBJECT_NULL), const_cast<char*>(line->GetParam("name")->AsPath("ai").c_str()));
m_newScriptName.push_back(NewScriptName(line->GetParam("type")->AsObjectType(OBJECT_NULL), const_cast<char*>(line->GetParam("name")->AsPath("ai").c_str())));
continue;
}
@ -3970,10 +3959,12 @@ void CRobotMain::ChangeColor()
}
//! Calculates the distance to the nearest object
float CRobotMain::SearchNearestObject(Math::Vector center, CObject *exclu)
namespace
{
float SearchNearestObject(CObjectManager* objMan, Math::Vector center, CObject* exclu)
{
float min = 100000.0f;
for (CObject* obj : m_objMan->GetAllObjects())
for (CObject* obj : objMan->GetAllObjects())
{
if (!obj->GetDetectable()) continue; // inactive?
if (IsObjectBeingTransported(obj)) continue;
@ -4017,6 +4008,7 @@ float CRobotMain::SearchNearestObject(Math::Vector center, CObject *exclu)
}
return min;
}
}
//! Calculates a free space
bool CRobotMain::FreeSpace(Math::Vector &center, float minRadius, float maxRadius,
@ -4038,7 +4030,7 @@ bool CRobotMain::FreeSpace(Math::Vector &center, float minRadius, float maxRadiu
pos.z = p.y;
pos.y = 0.0f;
m_terrain->AdjustToFloor(pos, true);
float dist = SearchNearestObject(pos, exclu);
float dist = SearchNearestObject(m_objMan.get(), pos, exclu);
if (dist >= space)
{
float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f);
@ -4067,7 +4059,7 @@ bool CRobotMain::FreeSpace(Math::Vector &center, float minRadius, float maxRadiu
pos.z = p.y;
pos.y = 0.0f;
m_terrain->AdjustToFloor(pos, true);
float dist = SearchNearestObject(pos, exclu);
float dist = SearchNearestObject(m_objMan.get(), pos, exclu);
if (dist >= space)
{
float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f);
@ -4103,7 +4095,7 @@ bool CRobotMain::FlatFreeSpace(Math::Vector &center, float minFlat, float minRad
pos.z = p.y;
pos.y = 0.0f;
m_terrain->AdjustToFloor(pos, true);
float dist = SearchNearestObject(pos, exclu);
float dist = SearchNearestObject(m_objMan.get(), pos, exclu);
if (dist >= space)
{
float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f);
@ -4136,7 +4128,7 @@ bool CRobotMain::FlatFreeSpace(Math::Vector &center, float minFlat, float minRad
pos.z = p.y;
pos.y = 0.0f;
m_terrain->AdjustToFloor(pos, true);
float dist = SearchNearestObject(pos, exclu);
float dist = SearchNearestObject(m_objMan.get(), pos, exclu);
if (dist >= space)
{
float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f);
@ -4160,7 +4152,7 @@ bool CRobotMain::FlatFreeSpace(Math::Vector &center, float minFlat, float minRad
float CRobotMain::GetFlatZoneRadius(Math::Vector center, float maxRadius,
CObject *exclu)
{
float dist = SearchNearestObject(center, exclu);
float dist = SearchNearestObject(m_objMan.get(), center, exclu);
if (dist == 0.0f) return 0.0f;
if (dist < maxRadius)
maxRadius = dist;
@ -4432,36 +4424,19 @@ bool CRobotMain::ReadFileStack(CObject *obj, FILE *file, int objRank)
return programmable->ReadStack(file);
}
//! Empty the list
void CRobotMain::FlushNewScriptName()
std::vector<std::string> CRobotMain::GetNewScriptNames(ObjectType type)
{
m_newScriptName.clear();
}
//! Adds a script name
void CRobotMain::AddNewScriptName(ObjectType type, const std::string& name)
std::vector<std::string> names;
for (const auto& newScript : m_newScriptName)
{
NewScriptName newscript;
newscript.type = type;
newscript.name = name;
m_newScriptName.push_back(newscript);
}
//! Seeks a script name for a given type
std::string CRobotMain::GetNewScriptName(ObjectType type, int rank)
if (newScript.type == type ||
newScript.type == OBJECT_NULL )
{
for (unsigned int i = 0; i < m_newScriptName.size(); i++)
{
if (m_newScriptName[i].type == type ||
m_newScriptName[i].type == OBJECT_NULL )
{
if (rank == 0) return m_newScriptName[i].name;
else rank --;
names.push_back(newScript.name);
}
}
return "";
return names;
}
@ -4960,56 +4935,81 @@ Error CRobotMain::ProcessEndMissionTakeForGroup(std::vector<CSceneEndCondition*>
Error CRobotMain::ProcessEndMissionTake()
{
// Sort end conditions by teams
std::map<int, std::vector<CSceneEndCondition*>> teams;
std::map<int, std::vector<CSceneEndCondition*>> teamsEndTake;
for (std::unique_ptr<CSceneEndCondition>& endTake : m_endTake)
teams[endTake->winTeam].push_back(endTake.get());
teamsEndTake[endTake->winTeam].push_back(endTake.get());
int teamCount = 0;
bool usesTeamConditions = false;
for (auto it : teams)
{
int team = it.first;
if (team == 0) continue;
usesTeamConditions = true;
if (!m_objMan->TeamExists(team)) continue;
teamCount++;
}
// This is just a smart way to check if we have any map values other than 0 defined
bool usesTeamConditions = teamsEndTake.size() > teamsEndTake.count(0);
if (!usesTeamConditions)
{
m_missionResult = ProcessEndMissionTakeForGroup(teams[0]);
m_missionResult = ProcessEndMissionTakeForGroup(teamsEndTake[0]);
}
else
{
// Special handling for teams
m_missionResult = ERR_MISSION_NOTERM;
if (teamCount == 0)
if (GetAllActiveTeams().empty())
{
GetLogger()->Info("All teams died, mission ended with failure\n");
m_missionResult = INFO_LOST;
GetLogger()->Info("All teams died, mission ended\n");
if (m_scoreboard)
{
std::string title, text, details_line;
GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS, title);
GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS_TEXT, text);
GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS_LINE, details_line);
std::string details = "";
for (int team : GetAllTeams())
{
if (!details.empty())
details += ", ";
details += StrUtils::Format(details_line.c_str(), GetTeamName(team).c_str(), m_scoreboard->GetScore(team));
}
m_ui->GetDialog()->StartInformation(
title,
text,
details,
false, true,
[&]() {
ChangePhase(PHASE_WIN);
}
);
m_endTakeWinDelay = 0.0f;
m_missionResult = ERR_OK;
}
else
{
for (auto it : teams)
m_missionResult = INFO_LOST;
}
}
else
{
for (auto it : teamsEndTake)
{
int team = it.first;
if (team == 0) continue;
if (!m_objMan->TeamExists(team)) continue;
if (m_teamFinished[team]) continue;
Error result = ProcessEndMissionTakeForGroup(it.second);
if (result == INFO_LOST || result == INFO_LOSTq)
{
GetLogger()->Info("Team %d lost\n", team);
m_displayText->DisplayText(("<<< Team "+boost::lexical_cast<std::string>(team)+" lost! >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 10.0f, Ui::TT_ERROR);
std::string text;
GetResource(RES_ERR, INFO_TEAM_DEAD, text);
text = StrUtils::Format(text.c_str(), GetTeamName(team).c_str());
m_displayText->DisplayText(text.c_str(), Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 10.0f, Ui::TT_ERROR);
m_displayText->SetEnable(false); // To prevent "bot destroyed" messages
m_objMan->DestroyTeam(team);
m_displayText->SetEnable(true);
m_teamFinished[team] = true;
}
else if (result == ERR_OK)
{
if (m_winDelay == 0.0f)
/*if (m_winDelay == 0.0f)
{
GetLogger()->Info("Team %d won\n", team);
@ -5025,7 +5025,16 @@ Error CRobotMain::ProcessEndMissionTake()
m_displayText->SetEnable(false);
}
m_missionResult = ERR_OK;
return ERR_OK;
return ERR_OK;*/
GetLogger()->Info("Team %d finished\n", team);
std::string text;
GetResource(RES_ERR, INFO_TEAM_FINISH, text);
text = StrUtils::Format(text.c_str(), GetTeamName(team).c_str());
m_displayText->DisplayText(text.c_str(), Math::Vector(0.0f,0.0f,0.0f));
if (m_scoreboard)
m_scoreboard->ProcessEndTake(team);
m_objMan->DestroyTeam(team, DestructionType::Win);
m_teamFinished[team] = true;
}
}
}
@ -5054,7 +5063,6 @@ Error CRobotMain::CheckEndMission(bool frame)
Error result = ProcessEndMissionTake();
if (result != ERR_MISSION_NOTERM) return result;
}
// Take action depending on m_missionResult
if (m_missionResult == INFO_LOSTq)
@ -5135,7 +5143,7 @@ const std::map<std::string, MinMax>& CRobotMain::GetObligatoryTokenList()
//! Indicates whether it is possible to control a driving robot
bool CRobotMain::GetTrainerPilot()
{
return m_trainerPilot;
return m_cheatTrainerPilot;
}
//! Indicates whether the scene is fixed, without interaction
@ -5158,7 +5166,7 @@ const std::string& CRobotMain::GetScriptFile()
bool CRobotMain::GetShowSoluce()
{
return m_showSoluce;
return m_cheatShowSoluce;
}
bool CRobotMain::GetSceneSoluce()
@ -5169,7 +5177,7 @@ bool CRobotMain::GetSceneSoluce()
bool CRobotMain::GetShowAll()
{
return m_showAll;
return m_cheatAllMission;
}
bool CRobotMain::GetRadar()
@ -5293,7 +5301,6 @@ void CRobotMain::UpdateSpeedLabel()
}
//! Creates interface shortcuts to the units
bool CRobotMain::CreateShortcuts()
{
if (m_phase != PHASE_SIMUL) return false;
@ -5638,7 +5645,7 @@ bool CRobotMain::IsBuildingEnabled(ObjectType type)
if(type == OBJECT_PARA) return IsBuildingEnabled(BUILD_PARA);
if(type == OBJECT_DESTROYER) return IsBuildingEnabled(BUILD_DESTROYER);
return true;
return false;
}
bool CRobotMain::IsResearchEnabled(ResearchType type)
@ -5683,11 +5690,6 @@ Error CRobotMain::CanBuildError(ObjectType type, int team)
return ERR_OK;
}
bool CRobotMain::CanBuild(ObjectType type, int team)
{
return CanBuildError(type, team) == ERR_OK;
}
Error CRobotMain::CanFactoryError(ObjectType type, int team)
{
ToolType tool = GetToolFromObject(type);
@ -5711,11 +5713,6 @@ Error CRobotMain::CanFactoryError(ObjectType type, int team)
return ERR_OK;
}
bool CRobotMain::CanFactory(ObjectType type, int team)
{
return CanFactoryError(type, team) == ERR_OK;
}
void CRobotMain::PushToSelectionHistory(CObject* obj)
{
if (!m_selectionHistory.empty() && m_selectionHistory.back() == obj)
@ -5795,8 +5792,12 @@ void CRobotMain::CreateCodeBattleInterface()
{
Math::Point pos, ddim;
int numTeams = m_scoreboard ? GetAllTeams().size() : 0;
assert(numTeams < EVENT_SCOREBOARD_MAX-EVENT_SCOREBOARD+1);
float textHeight = m_engine->GetText()->GetHeight(Gfx::FONT_COLOBOT, Gfx::FONT_SIZE_SMALL);
ddim.x = 100.0f/640.0f;
ddim.y = 100.0f/480.0f;
ddim.y = 100.0f/480.0f + numTeams * textHeight;
pos.x = 540.0f/640.0f;
pos.y = 100.0f/480.0f;
Ui::CWindow* pw = m_interface->CreateWindows(pos, ddim, 3, EVENT_WINDOW6);
@ -5804,8 +5805,10 @@ void CRobotMain::CreateCodeBattleInterface()
ddim.x = 100.0f/640.0f;
ddim.y = 16.0f/480.0f;
pos.x = 540.0f/640.0f;
pos.y = 178.0f/480.0f;
pw->CreateLabel(pos, ddim, 0, EVENT_LABEL0, "Code battle");
pos.y = 178.0f/480.0f + numTeams * textHeight;
std::string text;
GetResource(RES_EVENT, EVENT_LABEL_CODE_BATTLE, text);
pw->CreateLabel(pos, ddim, 0, EVENT_LABEL_CODE_BATTLE, text);
float titleBarSize = (11.0f/64.0f); // this is from the texture
ddim.x = 80.0f/640.0f;
@ -5820,6 +5823,84 @@ void CRobotMain::CreateCodeBattleInterface()
{
pw->CreateButton(pos, ddim, 13, EVENT_CODE_BATTLE_SPECTATOR);
}
pos.y += ddim.y;
ddim.y = textHeight;
int i = 0;
auto teams = GetAllTeams();
for (auto it = teams.rbegin(); it != teams.rend(); ++it)
{
int team = *it;
Ui::CControl* pl;
ddim.x = 55.0f/640.0f;
pl = m_codeBattleStarted
? static_cast<Ui::CControl*>(pw->CreateLabel(pos, ddim, 0, static_cast<EventType>(EVENT_SCOREBOARD+2*(numTeams-i-1)+0), "XXXXX"))
: static_cast<Ui::CControl*>(pw->CreateEdit( pos, ddim, 0, static_cast<EventType>(EVENT_SCOREBOARD+2*(numTeams-i-1)+0)));
pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT);
pl->SetFontSize(m_codeBattleStarted ? Gfx::FONT_SIZE_SMALL : Gfx::FONT_SIZE_SMALL*0.75f);
m_codeBattleStarted ? pl->SetName(GetTeamName(team)) : static_cast<Ui::CEdit*>(pl)->SetText(GetTeamName(team));
pos.x += 57.5f/640.0f;
ddim.x = 22.5f/640.0f;
pl = m_codeBattleStarted
? static_cast<Ui::CControl*>(pw->CreateLabel(pos, ddim, 0, static_cast<EventType>(EVENT_SCOREBOARD+2*(numTeams-i-1)+1), "???"))
: static_cast<Ui::CControl*>(pw->CreateEdit( pos, ddim, 0, static_cast<EventType>(EVENT_SCOREBOARD+2*(numTeams-i-1)+1)));
pl->SetTextAlign(Gfx::TEXT_ALIGN_RIGHT);
pl->SetFontSize(m_codeBattleStarted ? Gfx::FONT_SIZE_SMALL : Gfx::FONT_SIZE_SMALL*0.75f);
m_codeBattleStarted ? pl->SetName(StrUtils::ToString<int>(m_scoreboard->GetScore(team))) : static_cast<Ui::CEdit*>(pl)->SetText(StrUtils::ToString<int>(m_scoreboard->GetScore(team)));
pos.x -= 57.5f/640.0f;
pos.y += ddim.y;
i++;
}
}
}
void CRobotMain::ApplyCodeBattleInterface()
{
assert(GetMissionType() == MISSION_CODE_BATTLE);
if (!m_scoreboard) return;
Ui::CWindow* pw = static_cast<Ui::CWindow*>(m_interface->SearchControl(EVENT_WINDOW6));
assert(pw != nullptr);
int i = 0;
for (int team : GetAllTeams())
{
Ui::CEdit* pl;
pl = static_cast<Ui::CEdit*>(pw->SearchControl(static_cast<EventType>(EVENT_SCOREBOARD+2*i+0)));
assert(pl != nullptr);
m_teamNames[team] = pl->GetText(pl->GetTextLength());
pl = static_cast<Ui::CEdit*>(pw->SearchControl(static_cast<EventType>(EVENT_SCOREBOARD+2*i+1)));
assert(pl != nullptr);
m_scoreboard->SetScore(team, StrUtils::FromString<int>(pl->GetText(pl->GetTextLength())));
i++;
}
}
void CRobotMain::UpdateCodeBattleInterface()
{
assert(GetMissionType() == MISSION_CODE_BATTLE);
if (!m_scoreboard) return;
Ui::CWindow* pw = static_cast<Ui::CWindow*>(m_interface->SearchControl(EVENT_WINDOW6));
assert(pw != nullptr);
int i = 0;
for (int team : GetAllTeams())
{
Ui::CControl* pl;
pl = pw->SearchControl(static_cast<EventType>(EVENT_SCOREBOARD+2*i+0));
assert(pl != nullptr);
pl->SetName(GetTeamName(team));
pl = pw->SearchControl(static_cast<EventType>(EVENT_SCOREBOARD+2*i+1));
assert(pl != nullptr);
pl->SetName(StrUtils::ToString<int>(m_scoreboard->GetScore(team)));
i++;
}
}
@ -5866,3 +5947,55 @@ bool CRobotMain::GetDebugCrashSpheres()
{
return m_debugCrashSpheres;
}
void CRobotMain::PushToCommandHistory(std::string str)
{
if (!m_commandHistory.empty() && m_commandHistory.front() == str) // already in history
return;
m_commandHistory.push_front(str);
if (m_commandHistory.size() > 50) // to avoid infinite growth
m_commandHistory.pop_back();
}
std::string CRobotMain::GetNextFromCommandHistory()
{
if (m_commandHistory.empty() || static_cast<int>(m_commandHistory.size()) <= m_commandHistoryIndex + 1) // no next element
return "";
return m_commandHistory[++m_commandHistoryIndex];
}
std::string CRobotMain::GetPreviousFromCommandHistory()
{
if (m_commandHistory.empty() || m_commandHistoryIndex < 1) // first or none element selected
return "";
return m_commandHistory[--m_commandHistoryIndex];
}
CScoreboard* CRobotMain::GetScoreboard()
{
return m_scoreboard.get();
}
std::set<int> CRobotMain::GetAllTeams()
{
std::set<int> teams = GetAllActiveTeams();
for(auto& it : m_teamFinished)
{
teams.insert(it.first);
}
return teams;
}
std::set<int> CRobotMain::GetAllActiveTeams()
{
std::set<int> teams;
for (CObject* obj : m_objMan->GetAllObjects())
{
int team = obj->GetTeam();
if (team == 0) continue;
teams.insert(team);
}
return teams;
}

View File

@ -87,6 +87,7 @@ class CInput;
class CObjectManager;
class CSceneEndCondition;
class CAudioChangeCondition;
class CScoreboard;
class CPlayerProfile;
class CSettings;
class COldObject;
@ -120,6 +121,8 @@ struct NewScriptName
{
ObjectType type = OBJECT_NULL;
std::string name = "";
NewScriptName(ObjectType type, const std::string& name) : type(type), name(name) {}
};
@ -156,6 +159,17 @@ const int SATCOM_PROG = 4;
const int SATCOM_SOLUCE = 5;
const int SATCOM_MAX = 6;
/**
* \brief Main class managing the game world
*
* This is the main class of the whole game engine. It's main job is to manage main parts of the gameplay,
* like loading levels and checking for win conditions, but it's also a place where all things that don't fit
* elsewhere have landed.
*
* \todo In the future, it would be nice to refactor this class to remove as much unrelated stuff as possible
*
* \nosubgrouping
*/
class CRobotMain : public CSingleton<CRobotMain>
{
public:
@ -168,11 +182,16 @@ public:
Ui::CDisplayText* GetDisplayText();
CPauseManager* GetPauseManager();
/**
* \name Phase management
*/
//@{
void ChangePhase(Phase phase);
bool ProcessEvent(Event &event);
Phase GetPhase();
//@}
bool CreateShortcuts();
//! Load the scene for apperance customization
void ScenePerso();
void SetMovieLock(bool lock);
@ -187,16 +206,32 @@ public:
void SetFriendAim(bool friendAim);
bool GetFriendAim();
//! \name Simulation speed management
//@{
void SetSpeed(float speed);
float GetSpeed();
//@}
//! \brief Create the shortcuts at the top of the screen, if they should be visible
//! \see CMainShort::CreateShortcuts
bool CreateShortcuts();
//! \brief Update the shortcuts at the top of the screen
//! \see CMainShort::UpdateShortcuts
void UpdateShortcuts();
void SelectHuman();
//! Find the astronaut (::OBJECT_HUMAN) object
CObject* SearchHuman();
CObject* SearchToto();
CObject* SearchNearest(Math::Vector pos, CObject* exclu);
/**
* \brief Select an object
* \param obj Object to select
* \param displayError If true and the object is currently in error state, automatically display the error message
*
* \note This function automatically adds objects to selection history (see PushToSelectionHistory())
*/
bool SelectObject(CObject* obj, bool displayError=true);
//! Return the object that was selected at the start of the scene
CObject* GetSelectObject();
//! Deselect currently selected object
//! \return Object that was deselected
CObject* DeselectAll();
void ResetObject();
@ -251,9 +286,10 @@ public:
void ClearInterface();
void ChangeColor();
float SearchNearestObject(Math::Vector center, CObject *exclu);
bool FreeSpace(Math::Vector &center, float minRadius, float maxRadius, float space, CObject *exclu);
bool FlatFreeSpace(Math::Vector &center, float minFlat, float minRadius, float maxRadius, float space, CObject *exclu);
//! \name In-world indicators
//@{
float GetFlatZoneRadius(Math::Vector center, float maxRadius, CObject *exclu);
void HideDropZone(CObject* metal);
void ShowDropZone(CObject* metal, CObject* transporter);
@ -262,28 +298,38 @@ public:
float radius, float duration=SHOWLIMITTIME);
void StartShowLimit();
void FrameShowLimit(float rTime);
//@}
void SaveAllScript();
void SaveOneScript(CObject *obj);
bool SaveFileStack(CObject *obj, FILE *file, int objRank);
bool ReadFileStack(CObject *obj, FILE *file, int objRank);
void FlushNewScriptName();
void AddNewScriptName(ObjectType type, const std::string& name);
std::string GetNewScriptName(ObjectType type, int rank);
//! Return list of scripts to load to robot created in BotFactory
std::vector<std::string> GetNewScriptNames(ObjectType type);
//! Return the scoreboard manager
//! Note: this may return nullptr if the scoreboard is not enabled!
CScoreboard* GetScoreboard();
void SelectPlayer(std::string playerName);
CPlayerProfile* GetPlayerProfile();
/**
* \name Saved game read/write
*/
//@{
bool IOIsBusy();
bool IOWriteScene(std::string filename, std::string filecbot, std::string filescreenshot, const std::string& info, bool emergencySave = false);
void IOWriteSceneFinished();
CObject* IOReadScene(std::string filename, std::string filecbot);
void IOWriteObject(CLevelParserLine *line, CObject* obj, const std::string& programDir, int objRank);
CObject* IOReadObject(CLevelParserLine *line, const std::string& programDir, const std::string& objCounterText, float objectProgress, int objRank = -1);
//@}
int CreateSpot(Math::Vector pos, Gfx::Color color);
//! Find the currently selected object
CObject* GetSelect();
void DisplayError(Error err, CObject* pObj, float time=10.0f);
@ -298,12 +344,17 @@ public:
void StartMissionTimer();
/**
* \name Autosave management
*/
//@{
void SetAutosave(bool enable);
bool GetAutosave();
void SetAutosaveInterval(int interval);
int GetAutosaveInterval();
void SetAutosaveSlots(int slots);
int GetAutosaveSlots();
//@}
//! Enable mode where completing mission closes the game
void SetExitAfterMission(bool exit);
@ -311,49 +362,97 @@ public:
//! Returns true if player can interact with things manually
bool CanPlayerInteract();
/**
* \name Team definition management
*/
//@{
//! Returns team name for the given team id
const std::string& GetTeamName(int id);
//! Returns true if team-specific colored texture is available
bool IsTeamColorDefined(int id);
//@}
//! Get/set enabled buildings
/**
* \name EnableBuild/EnableResearch/DoneResearch
* Management of enabled buildings, enabled researches, and completed researches
*/
//@{
/**
* \brief Get enabled buildings
* \return Bitmask of BuildType values
*/
int GetEnableBuild();
/**
* \brief Set enabled buildings
* \param enableBuild Bitmask of BuildType values
*/
void SetEnableBuild(int enableBuild);
//@}
//! Get/set enabled researches
//@{
int GetEnableResearch();
void SetEnableResearch(int enableResearch);
//@}
//! Get/set done researches
//@{
int GetDoneResearch(int team);
void SetDoneResearch(int doneResearch, int team);
//@}
//! Returns true if the given building is enabled
//@{
/**
* \brief Get enabled researches
* \return Bitmask of ResearchType values
*/
int GetEnableResearch();
/**
* \brief Set enabled researches
* \param enableResearch Bitmask of ResearchType values
*/
void SetEnableResearch(int enableResearch);
/**
* \brief Get done researches
* \param team Team to get researches for
* \return Bitmask of ResearchType values
*/
int GetDoneResearch(int team = 0);
/**
* \brief Set done researches
* \param doneResearch Bitmask of ResearchType values
* \param team Team to set researches for
*/
void SetDoneResearch(int doneResearch, int team = 0);
//! \brief Check if the given building is enabled
bool IsBuildingEnabled(BuildType type);
//! \brief Check if the given building is enabled
bool IsBuildingEnabled(ObjectType type);
//@}
//! Returns true if the given research is enabled
//! \brief Check if the given research is enabled
bool IsResearchEnabled(ResearchType type);
//! Returns true if the given research is done
//! \brief Check if the given research is done
bool IsResearchDone(ResearchType type, int team);
//! Marks research as done
//! \brief Mark given research as done
void MarkResearchDone(ResearchType type, int team);
//! Retruns true if all requirements to build this object are met (EnableBuild + DoneResearch)
//@{
bool CanBuild(ObjectType type, int team);
/**
* \brief Check if all requirements to build this object are met (EnableBuild + DoneResearch)
* \return true if the building can be built, false otherwise
* \see CanBuildError() for a version which returns a specific reason for the build being denied
*/
inline bool CanBuild(ObjectType type, int team)
{
return CanBuildError(type, team) == ERR_OK;
}
/**
* \brief Check if all requirements to build this object are met (EnableBuild + DoneResearch)
* \return One of Error values - ::ERR_OK if the building can be built, ::ERR_BUILD_DISABLED or ::ERR_BUILD_RESEARCH otherwise
* \see CanBuild() for a version which returns a boolean
*/
Error CanBuildError(ObjectType type, int team);
//@}
//! Retruns true if all requirements to create this object in BotFactory are met (DoneResearch)
//@{
bool CanFactory(ObjectType type, int team);
/**
* \brief Check if all requirements to build this object in BotFactory are met (DoneResearch)
* \return true if the robot can be built, false otherwise
* \see CanFactoryError() for a version which returns a specific reason for the build being denied
*/
inline bool CanFactory(ObjectType type, int team)
{
return CanFactoryError(type, team) == ERR_OK;
}
/**
* \brief Check if all requirements to build this object in BotFactory are met (DoneResearch)
* \return One of Error values - ::ERR_OK if the robot can be built, ::ERR_BUILD_DISABLED or ::ERR_BUILD_RESEARCH otherwise
* \see CanFactory() for a version which returns a boolean
*/
Error CanFactoryError(ObjectType type, int team);
//@}
@ -364,12 +463,16 @@ public:
void StartDetectEffect(COldObject* object, CObject* target);
bool IsSelectable(CObject* obj);
//! Enable crash sphere debug rendering
void SetDebugCrashSpheres(bool draw);
//! Check if crash sphere debug rendering is enabled
bool GetDebugCrashSpheres();
//! Returns a set of all team IDs in the current level
std::set<int> GetAllTeams();
//! Returns a set of all team IDs in the current level that are still active
std::set<int> GetAllActiveTeams();
protected:
bool EventFrame(const Event &event);
bool EventObject(const Event &event);
@ -391,8 +494,11 @@ protected:
CObject* DetectObject(Math::Point pos);
void ChangeCamera();
void AbortMovie();
//! \brief Select an object, without deselecting the previous one
void SelectOneObject(CObject* obj, bool displayError=true);
void HelpObject();
//! \brief Switch to previous object
//! \see PopFromSelectionHistory()
bool DeselectObject();
void DeleteAllObjects();
void UpdateInfoText();
@ -408,11 +514,24 @@ protected:
void PushToSelectionHistory(CObject* obj);
CObject* PopFromSelectionHistory();
//! \name Code battle interface
//@{
void CreateCodeBattleInterface();
void UpdateCodeBattleInterface();
void ApplyCodeBattleInterface();
void DestroyCodeBattleInterface();
void SetCodeBattleSpectatorMode(bool mode);
//@}
void UpdateDebugCrashSpheres();
//! Adds element to the beginning of command history
void PushToCommandHistory(std::string obj);
//! Returns next/previous element from command history and updates index
//@{
std::string GetNextFromCommandHistory();
std::string GetPreviousFromCommandHistory();
//@}
protected:
CApplication* m_app = nullptr;
@ -472,9 +591,9 @@ protected:
ActivePause* m_freePhotoPause = nullptr;
bool m_cmdEdit = false;
ActivePause* m_cmdEditPause = nullptr;
bool m_selectInsect = false;
bool m_showSoluce = false;
bool m_showAll = false;
bool m_cheatSelectInsect = false;
bool m_cheatShowSoluce = false;
bool m_cheatAllMission = false;
bool m_cheatRadar = false;
bool m_shortCut = false;
std::string m_audioTrack;
@ -496,7 +615,7 @@ protected:
bool m_editLock = false; // edition in progress?
bool m_editFull = false; // edition in full screen?
bool m_hilite = false;
bool m_trainerPilot = false; // remote trainer?
bool m_cheatTrainerPilot = false; // remote trainer?
bool m_friendAim = false;
bool m_resetCreate = false;
bool m_mapShow = false;
@ -548,9 +667,15 @@ protected:
long m_endTakeResearch = 0;
float m_endTakeWinDelay = 0.0f;
float m_endTakeLostDelay = 0.0f;
//! Set to true for teams that have already finished
std::map<int, bool> m_teamFinished;
std::vector<std::unique_ptr<CAudioChangeCondition>> m_audioChange;
//! The scoreboard
//! If the scoreboard is not enabled for this level, this will be null
std::unique_ptr<CScoreboard> m_scoreboard;
std::map<std::string, MinMax> m_obligatoryTokens;
//! Enabled buildings
@ -585,4 +710,9 @@ protected:
std::deque<CObject*> m_selectionHistory;
bool m_debugCrashSpheres;
//! Cheat console command history
std::deque<std::string> m_commandHistory;
//! Index of currently selected element in command history
int m_commandHistoryIndex;
};

View File

@ -29,11 +29,13 @@
#include "object/interface/powered_object.h"
#include "object/interface/transportable_object.h"
#include <limits>
void CSceneCondition::Read(CLevelParserLine* line)
void CObjectCondition::Read(CLevelParserLine* line)
{
this->pos = line->GetParam("pos")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit;
this->dist = line->GetParam("dist")->AsFloat(8.0f)*g_unit;
this->dist = line->GetParam("dist")->AsFloat(std::numeric_limits<float>::infinity())*g_unit;
this->type = line->GetParam("type")->AsObjectType(OBJECT_NULL);
this->powermin = line->GetParam("powermin")->AsFloat(-1);
this->powermax = line->GetParam("powermax")->AsFloat(100);
@ -41,26 +43,13 @@ void CSceneCondition::Read(CLevelParserLine* line)
this->drive = line->GetParam("drive")->AsDriveType(DriveType::Other);
this->countTransported = line->GetParam("countTransported")->AsBool(true);
this->team = line->GetParam("team")->AsInt(0);
this->min = line->GetParam("min")->AsInt(1);
this->max = line->GetParam("max")->AsInt(9999);
}
int CSceneCondition::CountObjects()
bool CObjectCondition::CheckForObject(CObject* obj)
{
Math::Vector bPos = this->pos;
bPos.y = 0.0f;
Math::Vector oPos;
int nb = 0;
for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
{
if (!obj->GetActive()) continue;
if (!this->countTransported)
{
if (IsObjectBeingTransported(obj)) continue;
if (IsObjectBeingTransported(obj)) return false;
}
ObjectType type = obj->GetType();
@ -69,21 +58,21 @@ int CSceneCondition::CountObjects()
DriveType drive = GetDriveFromObject(type);
if (this->tool != ToolType::Other &&
tool != this->tool)
continue;
return false;
if (this->drive != DriveType::Other &&
drive != this->drive)
continue;
return false;
if (this->tool == ToolType::Other &&
this->drive == DriveType::Other &&
type != this->type &&
this->type != OBJECT_NULL)
continue;
return false;
if ((this->team > 0 && obj->GetTeam() != this->team) ||
(this->team < 0 && (obj->GetTeam() == -(this->team) || obj->GetTeam() == 0)))
continue;
return false;
float energyLevel = -1;
CPowerContainerObject* power = nullptr;
@ -105,16 +94,43 @@ int CSceneCondition::CountObjects()
energyLevel = power->GetEnergy();
if (power->GetCapacity() > 1.0f) energyLevel *= 10; // TODO: Who designed it like that ?!?!
}
if (energyLevel < this->powermin || energyLevel > this->powermax) continue;
if (energyLevel < this->powermin || energyLevel > this->powermax) return false;
Math::Vector oPos;
if (IsObjectBeingTransported(obj))
oPos = dynamic_cast<CTransportableObject*>(obj)->GetTransporter()->GetPosition();
else
oPos = obj->GetPosition();
oPos.y = 0.0f;
Math::Vector bPos = this->pos;
bPos.y = 0.0f;
if (Math::DistanceProjected(oPos, bPos) <= this->dist)
return true;
return false;
}
void CSceneCondition::Read(CLevelParserLine* line)
{
CObjectCondition::Read(line);
// Scene conditions STILL use a different default value
// See issue #759
this->dist = line->GetParam("dist")->AsFloat(8.0f)*g_unit;
this->min = line->GetParam("min")->AsInt(1);
this->max = line->GetParam("max")->AsInt(9999);
}
int CSceneCondition::CountObjects()
{
int nb = 0;
for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
{
if (!obj->GetActive()) continue;
if (!CheckForObject(obj)) continue;
nb ++;
}
return nb;
@ -126,7 +142,6 @@ bool CSceneCondition::Check()
return nb >= this->min && nb <= this->max;
}
void CSceneEndCondition::Read(CLevelParserLine* line)
{
CSceneCondition::Read(line);

Some files were not shown because too many files have changed in this diff Show More